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

📄 dbrfx.cpp

📁 vc6.0完整版
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"

#ifdef AFX_DB_SEG
#pragma code_seg(AFX_DB_SEG)
#endif

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

/////////////////////////////////////////////////////////////////////////////
// CDBByteArray db specific class for holding byte array data
class CDBByteArray : public CByteArray
{
	DECLARE_DYNAMIC(CDBByteArray)

// Operations
	void SetLength(int nNewSize);
};

inline void CDBByteArray::SetLength(int nNewSize)
{
	// Can't grow buffer since ODBC has been SQLBindCol'd on it.
	ASSERT(nNewSize <= m_nMaxSize);
	m_nSize = nNewSize;
}

//////////////////////////////////////////////////////////////////////////////
// CFieldExchange

CFieldExchange::CFieldExchange(UINT nOperation, CRecordset* prs, void* pvField)
{
#ifdef _DEBUG
	ASSERT(nOperation >= BindParam && nOperation <= DumpField);
#endif
	ASSERT_VALID(prs);
	ASSERT(prs->m_hstmt != SQL_NULL_HSTMT);

	m_nFieldType = (UINT) noFieldType;
	m_nOperation = nOperation;
	m_prs = prs;
	m_pvField = pvField;

	m_nFields = 0;
	m_nParams = 0;
	m_nParamFields = 0;
	m_bField = FALSE;
	m_pstr = NULL;
	m_hstmt = SQL_NULL_HSTMT;

	m_lDefaultLBFetchSize = 0x00010000;
	m_lDefaultLBReallocSize = 0x00010000;
}

BOOL CFieldExchange::IsFieldType(UINT* pnField)
{
	if (m_nFieldType == outputColumn)
	{
		*pnField = ++m_nFields;
		// Recordset's m_nFields must match number of Fields!
		ASSERT(m_nFields <= m_prs->m_nFields);
	}
	else
	{
		// Make sure SetFieldType was called
		ASSERT(m_nFieldType == inputParam ||
			m_nFieldType == outputParam ||
			m_nFieldType == inoutParam);

		*pnField = ++m_nParams;
		// Recordset's m_nParams must match number of Params!
		ASSERT(m_nParams <= m_prs->m_nParams);
	}

	if (m_nOperation == BindParam || m_nOperation == RebindParam)
	{
		// only valid on a param field type
		return m_nFieldType != outputColumn;
	}
	else
	{
		// valid only on an outputColumn field type
		return m_nFieldType == outputColumn;
	}
}

// Default implementation for RFX functions
void CFieldExchange::Default(LPCTSTR szName,
	void* pv, LONG* plLength, int nCType, UINT cbValue, UINT cbPrecision)
{
	RETCODE nRetCode;
	UINT nField = (m_nFieldType == outputColumn)? m_nFields: m_nParams;
	switch (m_nOperation)
	{
	case BindParam:
		if (m_prs->IsParamStatusNull(nField - 1))
			*plLength = SQL_NULL_DATA;
		else
			*plLength = cbValue;
		// For params, CType is same as SQL type
		AFX_SQL_SYNC(::SQLBindParameter(m_hstmt, (UWORD)nField,
			(SWORD)m_nFieldType, (SWORD)nCType, (SWORD)nCType, cbPrecision, 0,
			pv, 0, plLength));
		if (nRetCode != SQL_SUCCESS)
			m_prs->ThrowDBException(nRetCode, m_hstmt);

		// Add the member address to the param map
		m_prs->m_mapParamIndex.SetAt(pv, (void*)nField);
		return;

	case RebindParam:
		// Only need to reset param length
		*plLength = m_prs->IsParamStatusNull(nField - 1) ? SQL_NULL_DATA : cbValue;
		return;

	case BindFieldForUpdate:
		if (!m_prs->IsFieldStatusDirty(nField - 1))
		{
			// If not dirty, set length to SQL_IGNORE for SQLSetPos updates
			*plLength = SQL_IGNORE;
		}
		else if (!m_prs->IsFieldStatusNull(nField - 1))
		{
			// Reset the length as it may have changed for var length fields
			*plLength = cbValue;
		}
		return;


	case UnbindFieldForUpdate:
		// Reset bound length to actual length to clear SQL_IGNOREs
		if (!m_prs->IsFieldStatusDirty(nField - 1))
			*plLength = cbValue;
		return;

	case BindFieldToColumn:
		AFX_SQL_SYNC(::SQLBindCol(m_prs->m_hstmt, (UWORD)nField, (SWORD)nCType,
			pv, cbValue, plLength));
		if (!m_prs->Check(nRetCode))
			m_prs->ThrowDBException(nRetCode);

		// Add the member address to the field map
		m_prs->m_mapFieldIndex.SetAt(pv, (void*)nField);
		return;

	case Name:
		if (m_prs->IsFieldStatusDirty(nField - 1))
		{
			// We require a name
			ASSERT(lstrlen(szName) != 0);

			*m_pstr += szName;
			*m_pstr += m_lpszSeparator;
		}
		return;

	case NameValue:
		if (m_prs->IsFieldStatusDirty(nField - 1))
		{
			*m_pstr += szName;
			*m_pstr += '=';
		}

		// Fall through
	case Value:
		if (m_prs->IsFieldStatusDirty(nField - 1))
		{
			// If user marked column NULL, reflect this in length
			if (m_prs->IsFieldStatusNull(nField - 1))
				*plLength = SQL_NULL_DATA;
			else
				*plLength = cbValue;

			// If optimizing for bulk add, only need lengths set correctly
			if(!(m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
			{
				*m_pstr += '?';
				*m_pstr += m_lpszSeparator;
				m_nParamFields++;

				// Assumes all bound fields BEFORE unbound fields
				CODBCFieldInfo* pODBCInfo =
					&m_prs->m_rgODBCFieldInfos[nField - 1];

				AFX_SQL_SYNC(::SQLBindParameter(m_hstmt,
					(UWORD)m_nParamFields, SQL_PARAM_INPUT,
					(SWORD)nCType, pODBCInfo->m_nSQLType,
					pODBCInfo->m_nPrecision, pODBCInfo->m_nScale,
					pv, 0, plLength));
				if (nRetCode != SQL_SUCCESS)
					m_prs->ThrowDBException(nRetCode, m_hstmt);
			}
		}
		return;

	case MarkForUpdate:
		{
			// Get the field data
			CFieldInfo* pInfo = &m_prs->m_rgFieldInfos[nField - 1];

			// If user changed field value from previous value, mark field dirty
			if ((pInfo->m_bStatus & AFX_SQL_FIELD_FLAG_NULL))
			{
				if (!m_prs->IsFieldStatusNull(nField - 1))
					m_prs->SetDirtyFieldStatus(nField - 1);
			}
			else
			{
				// Saved field is not NULL. current field null, so field dirty
				BOOL bDirty = m_prs->IsFieldStatusNull(nField - 1);

				// If values differ, then field dirty
				void* pvDataCache;

				if (pInfo->m_nDataType == AFX_RFX_BOOL ||
					pInfo->m_nDataType == AFX_RFX_BYTE ||
					pInfo->m_nDataType == AFX_RFX_INT ||
					pInfo->m_nDataType == AFX_RFX_LONG ||
					pInfo->m_nDataType == AFX_RFX_SINGLE)
				{
					// If caching data by value, pass a ref
					pvDataCache = &pInfo->m_pvDataCache;
				}
				else
					pvDataCache = pInfo->m_pvDataCache;

				if (bDirty || !AfxCompareValueByRef(pv, pvDataCache, pInfo->m_nDataType))
					m_prs->SetDirtyFieldStatus(nField - 1);
			}

#ifdef _DEBUG
			// Field address must not change - ODBC's SQLBindCol depends upon this
			void* pvBind;

			switch (pInfo->m_nDataType)
			{
			default:
				pvBind = pv;
				break;

			case AFX_RFX_LPTSTR:
#ifdef _UNICODE
				pvBind = m_prs->m_pvFieldProxy[nField-1];
#else // !_UNICODE
				pvBind = pv;
#endif
				break;

			case AFX_RFX_TEXT:
#ifdef _UNICODE
				pvBind = m_prs->m_pvFieldProxy[nField-1];
#else // !_UNICODE
				{
					pvBind = ((CString*)pv)->GetBuffer(0);
					((CString*)pv)->ReleaseBuffer();
				}
#endif
				break;

			case AFX_RFX_OLEDATE:
			case AFX_RFX_DATE:
				pvBind = m_prs->m_pvFieldProxy[nField-1];
				break;

			case AFX_RFX_BINARY:
				pvBind = ((CByteArray*)pv)->GetData();
				break;
			}

			if (pInfo->m_pvBindAddress != pvBind)
			{
				TRACE1("Error: field address (column %u) has changed!\n",
					nField);
				ASSERT(FALSE);
			}
#endif // _DEBUG

			if ((m_pvField == NULL  || m_pvField == pv) &&
				m_prs->IsFieldStatusDirty(nField - 1))
			{
				m_bField = TRUE;
			}
		}
		return;

	case StoreField:
		AfxStoreField(*m_prs, nField, pv);
		return;

	case LoadField:
		AfxLoadField(*m_prs, nField, pv, plLength);
		return;

	default:
		ASSERT(FALSE);
	}
}

void AFXAPI RFX_Text(CFieldExchange* pFX, LPCTSTR szName,
	LPTSTR value, int nMaxLength, int nColumnType, short nScale)
{
	ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
	ASSERT(AfxIsValidString(szName));
	ASSERT(AfxIsValidAddress(value, nMaxLength));

	RETCODE nRetCode;
	UINT nField;
	if (!pFX->IsFieldType(&nField))
		return;

	LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
		nField - 1, pFX->m_nFieldType);
	switch (pFX->m_nOperation)
	{
	default:
		pFX->Default(szName, value, plLength,
			SQL_C_CHAR, lstrlen(value), nMaxLength);
		return;

	case CFieldExchange::BindParam:
		{
			void* pvParam = value; // will be overwritten if UNICODE

#ifdef _UNICODE
			// Must use proxy to translate unicode data into non-unicode param
			pFX->m_prs->m_bRebindParams = TRUE;

			// Allocate proxy array if necessary
			if (pFX->m_prs->m_pvParamProxy == NULL)
			{
				pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
				memset(pFX->m_prs->m_pvParamProxy, 0,
					pFX->m_prs->m_nParams*sizeof(void*));
				pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
			}

			// Allocate non-unicode string to nMaxLength if necessary for SQLBindParameter
			if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
			{
				pvParam = new CHAR[nMaxLength+1];
				pFX->m_prs->m_pvParamProxy[nField-1] = pvParam;
			}
			else
				pvParam = pFX->m_prs->m_pvParamProxy[nField-1];

			// Now fill in the data value
			USES_CONVERSION;
			lstrcpyA((char*)pvParam, T2A((LPCTSTR)value));
#endif // _UNICODE

			*plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
				SQL_NULL_DATA : SQL_NTS;

			AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
				 (SWORD)pFX->m_nFieldType, SQL_C_CHAR, (SWORD)nColumnType,
				 nMaxLength, nScale, pvParam, nMaxLength, plLength));

			if (nRetCode != SQL_SUCCESS)
				pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);

			// Add the member address to the param map
			pFX->m_prs->m_mapParamIndex.SetAt(value, (void*)nField);
		}
		return;

#ifdef _UNICODE
	case CFieldExchange::RebindParam:
		*plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
			SQL_NULL_DATA : SQL_NTS;
		if (pFX->m_prs->m_nProxyParams != 0)
		{
			// Fill buffer (expected by SQLBindParameter) with new param data
			USES_CONVERSION;
			LPSTR lpszParam = (LPSTR)pFX->m_prs->m_pvParamProxy[nField-1];
			lstrcpyA(lpszParam, T2A((LPCTSTR)value));
		}
		return;
#endif // _UNICODE

	case CFieldExchange::BindFieldToColumn:
		{
			// Assumes all bound fields BEFORE unbound fields
			CODBCFieldInfo* pODBCInfo =
				&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
			UINT cbColumn = pODBCInfo->m_nPrecision;

			switch (pODBCInfo->m_nSQLType)
			{
			default:
#ifdef _DEBUG
				// Warn of possible field schema mismatch
				if (afxTraceFlags & traceDatabase)
					TRACE1("Warning: string converted from SQL type %ld.\n",
						pODBCInfo->m_nSQLType);
#endif // _DEBUG

				// Add room for extra information like sign, decimal point, etc.
				cbColumn += 10;
				break;

			case SQL_LONGVARCHAR:
			case SQL_CHAR:
			case SQL_VARCHAR:
				break;

			case SQL_FLOAT:
			case SQL_REAL:
			case SQL_DOUBLE:
				// Add room for sign, decimal point and " E +XXX"
				cbColumn += 10;
				break;

			case SQL_DECIMAL:
			case SQL_NUMERIC:
				// Add room for sign and decimal point
				cbColumn += 2;
				break;

			case SQL_TIMESTAMP:
			case SQL_DATE:
			case SQL_TIME:
				// May need extra space, i.e. "{TS mm/dd/yyyy hh:mm:ss}"
				cbColumn += 10;
				break;

			case SQL_TINYINT:
			case SQL_SMALLINT:
			case SQL_INTEGER:
			case SQL_BIGINT:
				// Add room for sign
				cbColumn += 1;
				break;
			}

			// Constrain to user specified max length, subject to 256 byte min
			if (cbColumn > (UINT)nMaxLength || cbColumn < 256)
				cbColumn = nMaxLength;

			// Set up binding addres

			void* pvData = value;   // overwritten if _UNICODE
			value[cbColumn] = '\0';

#ifdef _UNICODE
			// Allocate proxy array if necessary
			if (pFX->m_prs->m_pvFieldProxy == NULL)
			{
				pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
				memset(pFX->m_prs->m_pvFieldProxy, 0,
					pFX->m_prs->m_nFields*sizeof(void*));
				pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
			}

			// Allocate non-unicode string for SQLBindCol (not necessary on Requery)
			if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
				pFX->m_prs->m_pvFieldProxy[nField-1] = new CHAR[cbColumn+2];

			pvData = pFX->m_prs->m_pvFieldProxy[nField-1];
#endif // _UNICODE

			AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
				SQL_C_CHAR, pvData, cbColumn+1, plLength));
			if (!pFX->m_prs->Check(nRetCode))
				pFX->m_prs->ThrowDBException(nRetCode);

			// Add the member address to the field map
			pFX->m_prs->m_mapFieldIndex.SetAt(value, (void*)nField);
		}
		return;

⌨️ 快捷键说明

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