/////////////////////////////////////////////////////////////////
// HRESULT CRow::SetupColAccess
//
/////////////////////////////////////////////////////////////////
HRESULT CRow::SetupColAccess(BINDCOLS eBindCols)
{
	HRESULT hr = S_OK;
	DBLENGTH dwOffset = 0;
	ULONG i;

	//Only capable of the Following Converions (for Display)
	DWORD  dwMaxLength		= GetOptions()->m_dwMaxLength;
	DWORD  dwAccessorOpts	= GetOptions()->m_dwAccessorOpts;
	
	if(m_pIColumnsInfo == NULL)
		return E_FAIL;

	//GetColumnInfo
	GetColInfo();

	//Alloc the space to hold the ColumnAccess structs
	ULONG cBindings = 0;
	DBBINDING* rgBindings = NULL;
	SAFE_ALLOC(m_rgColAccess, DBCOLUMNACCESS, m_ColumnInfo.GetCount());
	SAFE_ALLOC(rgBindings, DBBINDING, m_ColumnInfo.GetCount());

	//Figure out how big to make the buffer...
	for(i=0; i<m_ColumnInfo.GetCount(); i++)
	{
		//Offset
		m_rgColAccess[i].cbMaxLen = GetMaxDisplaySize(GetOptions()->GetBindingType(m_ColumnInfo[i].wType), m_ColumnInfo[i].wType, m_ColumnInfo[i].ulColumnSize, dwMaxLength);
		dwOffset = ROUNDUP( dwOffset + m_rgColAccess[i].cbMaxLen );
	}

	//Size for pData
	SAFE_REALLOC(m_pData, BYTE, dwOffset);
	
	dwOffset = 0;
	m_cColAccess = 0;
	cBindings = 0;
	for(i=0; i<m_ColumnInfo.GetCount(); i++) 
	{
		DBCOLUMNINFO*	pColInfo	= &m_ColumnInfo[i];
		DBCOLUMNACCESS*	pColAccess	= &m_rgColAccess[m_cColAccess];
		DBBINDING*		pBinding	= &rgBindings[cBindings];

		//Setup the Bindings
		pColAccess->columnid		= pColInfo->columnid;
		pColAccess->bPrecision		= pColInfo->bPrecision;
		pColAccess->bScale			= pColInfo->bScale;
		pColAccess->wType			= GetOptions()->GetBindingType(pColInfo->wType);
		pColAccess->cbDataLen		= 0;

		//NOTE: This is setup above in the Previous for loop...
		pColAccess->cbMaxLen		= m_rgColAccess[i].cbMaxLen; 
		
		//BLOB or IUnknown Bindings
		if(pColAccess->wType == DBTYPE_IUNKNOWN || pColInfo->wType == DBTYPE_IUNKNOWN || 
			(pColInfo->dwFlags & DBCOLUMNFLAGS_ISLONG && (dwAccessorOpts & (ACCESSOR_BLOB_ISEQSTREAM|ACCESSOR_BLOB_ILOCKBYTES|ACCESSOR_BLOB_ISTORAGE|ACCESSOR_BLOB_ISTREAM))))
		{
			pColAccess->wType		= DBTYPE_IUNKNOWN;
			pColAccess->cbMaxLen	= sizeof(IUnknown*);
		}	
		
		//If the consumer requested not to bind the Value in Options, then set pData = NULL
		//This is how the 2.5 spec says to indicate VALUE is not bound (since their is no dwPart).
		pColAccess->pData			= NULL;
		if(dwAccessorOpts & ACCESSOR_BIND_VALUE)
			pColAccess->pData		= (BYTE*)m_pData + dwOffset;
						
		//Initialize the Status to an error, so we don't end up freeing outofline 
		//data we haven't retreived yet...
		pColAccess->dwStatus		= DBSTATUS_E_UNAVAILABLE;

		//Special Handling for other non-OLE DB defined convertable types to WSTR
		//NOTE: The spec requires all supported types to be converted to 
		//WSTR, but this only applies where the OLE DB conversion is defined.
		//Some are not defined so we need to bind nativly.
		switch(pColInfo->wType)
		{
			case DBTYPE_IUNKNOWN:
			case DBTYPE_IDISPATCH:
				pColAccess->wType		= pColInfo->wType;
				pColAccess->cbMaxLen	= sizeof(IUnknown*);
				break;

			case DBTYPE_HCHAPTER:
				pColAccess->wType		= pColInfo->wType;
				pColAccess->cbMaxLen	= sizeof(HCHAPTER);
				break;

			default:
				//DBTYPE_VECTOR
				if(pColInfo->wType	& DBTYPE_VECTOR)
				{
					pColAccess->wType	= pColInfo->wType;
					pColAccess->cbMaxLen= sizeof(DBVECTOR);
				}
				
				//DBTYPE_ARRAY
				if(pColInfo->wType	& DBTYPE_ARRAY)
				{
					pColAccess->wType	= pColInfo->wType;
					pColAccess->cbMaxLen= sizeof(SAFEARRAY*);
				}
				break;
		};

		//Offset
		dwOffset += pColAccess->cbMaxLen;
		dwOffset = ROUNDUP( dwOffset );

		//Build a real simple binding on top of this ColumnAccess struct.
		//The reason is all of our data manipulations routines deal with binding structs, so instead
		//have having numerous code lines, we will just map this to a binding struct...
		pBinding->iOrdinal		= pColInfo->iOrdinal;
		pBinding->obStatus		= (DBBYTEOFFSET)((BYTE*)&pColAccess->dwStatus - (BYTE*)m_pData);
		pBinding->obLength		= (DBBYTEOFFSET)((BYTE*)&pColAccess->cbDataLen - (BYTE*)m_pData);
		pBinding->obValue		= (DBBYTEOFFSET)((BYTE*)pColAccess->pData - (BYTE*)m_pData);

		pBinding->pTypeInfo		= NULL;
		pBinding->pObject		= NULL;
		pBinding->pBindExt		= NULL;

		pBinding->dwPart		= DBPART_LENGTH|DBPART_STATUS;
		if(pColAccess->pData)
			pBinding->dwPart	|= DBPART_VALUE;

		pBinding->dwMemOwner	= (dwAccessorOpts & ACCESSOR_OWNED_PROVIDER) ? DBMEMOWNER_PROVIDEROWNED : DBMEMOWNER_CLIENTOWNED;
		pBinding->eParamIO		= DBPARAMIO_NOTPARAM;
		
		pBinding->cbMaxLen		= pColAccess->cbMaxLen;
		pBinding->dwFlags		= 0;
		pBinding->wType			= pColAccess->wType;

		pBinding->bPrecision	= pColAccess->bPrecision;
		pBinding->bScale		= pColAccess->bScale;

		//Do we real want this column?		
		switch(eBindCols)
		{
			case BIND_ALLCOLS:
				m_cColAccess++;
				cBindings++;
				break;

			case BIND_ALLCOLSEXPECTBOOKMARK:
				if(pColInfo->iOrdinal != 0)
				{
					m_cColAccess++;
					cBindings++;
				}
				break;

			case BIND_UPDATEABLECOLS:
				if(pColInfo->dwFlags & DBCOLUMNFLAGS_WRITE || pColInfo->dwFlags & DBCOLUMNFLAGS_WRITEUNKNOWN)
				{
					m_cColAccess++;
					cBindings++;
				}
				break;

			default:
				ASSERT(!"Unhandled Type!");
				break;
		}
	}

CLEANUP:
	m_Bindings.Attach(cBindings, rgBindings);
	return hr;
}
 /**
 Get maximum display size.

 @return Display size.
 */
 virtual std::size_t GetMaxDisplaySize()
 {
  return GetMaxDisplaySize(GetServerType());
 }