#ifndef __I_COLUMNS_ROWSET_IMPL__INCLUDED__
#define __I_COLUMNS_ROWSET_IMPL__INCLUDED__
#include <atlcom.h>
#include <atldb.h>
#include <comutil.h>
#define PROVIDER_COLUMN_ENTRY_DBID(name, dbid, ordinal, member) \
{ \
(LPOLESTR)OLESTR(name), \
(ITypeInfo*)NULL, \
(ULONG)ordinal, \
DBCOLUMNFLAGS_ISFIXEDLENGTH, \
(ULONG)sizeof(((_Class*)0)->member), \
_GetOleDBType(((_Class*)0)->member), \
(BYTE)0, \
(BYTE)0, \
{ \
EXPANDGUID(dbid.uGuid.guid), \
(DWORD)dbid.eKind, \
(LPOLESTR)dbid.uName.ulPropid\
}, \
offsetof(_Class, member) \
},
class CColumnsRowsetRow
{
public:
WCHAR m_DBCOLUMN_IDNAME[129];
GUID m_DBCOLUMN_GUID;
ULONG m_DBCOLUMN_PROPID;
WCHAR m_DBCOLUMN_NAME[129];
ULONG m_DBCOLUMN_NUMBER;
USHORT m_DBCOLUMN_TYPE;
IUnknown *m_DBCOLUMN_TYPEINFO;
ULONG m_DBCOLUMN_COLUMNSIZE;
USHORT m_DBCOLUMN_PRECISION;
USHORT m_DBCOLUMN_SCALE;
ULONG m_DBCOLUMN_FLAGS;
WCHAR m_DBCOLUMN_BASECOLUMNNAME[129];
WCHAR m_DBCOLUMN_BASETABLENAME[129];
BOOL m_DBCOLUMN_KEYCOLUMN;
CColumnsRowsetRow()
{
ClearMembers();
}
void ClearMembers()
{
m_DBCOLUMN_IDNAME[0] = NULL;
m_DBCOLUMN_GUID = GUID_NULL;
m_DBCOLUMN_PROPID = 0;
m_DBCOLUMN_NAME[0] = 0;
m_DBCOLUMN_NUMBER = 0;
m_DBCOLUMN_TYPE = 0;
m_DBCOLUMN_TYPEINFO = 0;
m_DBCOLUMN_COLUMNSIZE = 0;
m_DBCOLUMN_PRECISION = 0;
m_DBCOLUMN_SCALE = 0;
m_DBCOLUMN_FLAGS = 0;
m_DBCOLUMN_BASECOLUMNNAME[0] = NULL;
m_DBCOLUMN_BASETABLENAME[0] = NULL;
m_DBCOLUMN_KEYCOLUMN = FALSE;
}
BEGIN_PROVIDER_COLUMN_MAP(CColumnsRowsetRow)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_IDNAME", DBCOLUMN_IDNAME, 1, m_DBCOLUMN_IDNAME)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_GUID", DBCOLUMN_GUID, 2, m_DBCOLUMN_GUID)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_PROPID", DBCOLUMN_PROPID, 3, m_DBCOLUMN_PROPID)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_NAME", DBCOLUMN_NAME, 4, m_DBCOLUMN_NAME)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_NUMBER", DBCOLUMN_NUMBER, 5, m_DBCOLUMN_NUMBER)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_TYPE", DBCOLUMN_TYPE, 6, m_DBCOLUMN_TYPE)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_TYPEINFO", DBCOLUMN_TYPEINFO, 7, m_DBCOLUMN_TYPEINFO)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_COLUMNSIZE", DBCOLUMN_COLUMNSIZE, 8, m_DBCOLUMN_COLUMNSIZE)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_PRECISION", DBCOLUMN_PRECISION, 9, m_DBCOLUMN_PRECISION)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_SCALE", DBCOLUMN_SCALE, 10, m_DBCOLUMN_SCALE)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_FLAGS", DBCOLUMN_FLAGS, 11, m_DBCOLUMN_FLAGS)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_BASECOLUMNNAME", DBCOLUMN_BASECOLUMNNAME, 12, m_DBCOLUMN_BASECOLUMNNAME)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_BASETABLENAME", DBCOLUMN_BASETABLENAME, 13, m_DBCOLUMN_BASETABLENAME)
PROVIDER_COLUMN_ENTRY_DBID("DBCOLUMN_KEYCOLUMN", DBCOLUMN_KEYCOLUMN, 14, m_DBCOLUMN_KEYCOLUMN)
END_PROVIDER_COLUMN_MAP()
};
template <class T, class CreatorClass>
class ATL_NO_VTABLE IColumnsRowsetImpl : public IColumnsRowset
{
public:
class CColumnsRowsetRowset :
public CRowsetImpl< CColumnsRowsetRowset , CColumnsRowsetRow, CreatorClass>
{
public:
HRESULT PopulateRowset(IColumnsRowsetImpl *pRowset, ULONG numCols, DBCOLUMNINFO *pColInfo)
{
for (ULONG i = 0 ; i < numCols; i++)
{
// copy data out of the pColInfo struct and into the
// rowset array
CColumnsRowsetRow data;
// Should select the name correctly, rather than just assuming we'll use the name and
// not the guid and propid..
lstrcpynW(data.m_DBCOLUMN_IDNAME, pColInfo[i].pwszName , sizeof(data.m_DBCOLUMN_IDNAME));
data.m_DBCOLUMN_GUID = GUID_NULL;
data.m_DBCOLUMN_PROPID = 0;
lstrcpynW(data.m_DBCOLUMN_NAME, pColInfo[i].pwszName , sizeof(data.m_DBCOLUMN_NAME));
data.m_DBCOLUMN_NUMBER = pColInfo[i].iOrdinal;
data.m_DBCOLUMN_TYPE = pColInfo[i].wType;
data.m_DBCOLUMN_TYPEINFO = pColInfo[i].pTypeInfo;
data.m_DBCOLUMN_COLUMNSIZE = pColInfo[i].ulColumnSize;
data.m_DBCOLUMN_PRECISION = pColInfo[i].bPrecision;
data.m_DBCOLUMN_SCALE = pColInfo[i].bScale;
data.m_DBCOLUMN_FLAGS = pColInfo[i].dwFlags;
lstrcpynW(data.m_DBCOLUMN_BASECOLUMNNAME, pColInfo[i].pwszName, sizeof(data.m_DBCOLUMN_BASECOLUMNNAME));
lstrcpynW(data.m_DBCOLUMN_BASETABLENAME, pRowset->GetTableName(), sizeof(data.m_DBCOLUMN_BASETABLENAME));
data.m_DBCOLUMN_KEYCOLUMN = (pColInfo[i].iOrdinal == 0) || (pColInfo[i].dwFlags & DBCOLUMNFLAGS_ISROWID);
// Base the keycolumn decision on the flags too?
// Keycolumn is only used if the column has been displayed :( Pity as this renders the bookmarks
// useless..
if (!m_rgRowData.Add(data))
{
return E_OUTOFMEMORY;
}
}
return S_OK;
}
};
STDMETHOD(GetAvailableColumns)(
ULONG *pcOptColumns,
DBID **prgOptColumns)
{
ATLTRACE2(atlTraceDBProvider, 0, "IColumnsRowsetImpl::GetAvailableColumns()\n");
if (!pcOptColumns || !prgOptColumns)
{
return E_INVALIDARG;
}
const ULONG c_numOptColumns = 3;
*pcOptColumns = c_numOptColumns;
DBID *pOptCols = (DBID*)CoTaskMemAlloc(sizeof(DBID) * c_numOptColumns);
memset(pOptCols, 0, sizeof(DBID) * c_numOptColumns);
pOptCols[0] = DBCOLUMN_BASETABLENAME;
pOptCols[1] = DBCOLUMN_BASECOLUMNNAME;
pOptCols[2] = DBCOLUMN_KEYCOLUMN;
*pcOptColumns = c_numOptColumns;
*prgOptColumns = pOptCols;
return S_OK;
}
STDMETHOD(GetColumnsRowset)(
IUnknown *pUnkOuter,
ULONG cOptColumns,
const DBID rgOptColumns[],
REFIID riid,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
IUnknown **ppColRowset)
{
ATLTRACE2(atlTraceDBProvider, 0, "IColumnsRowsetImpl::GetColumnsRowset()\n");
// need to create our columns rowset,
// then populate it from the actual rowset that we represent...
// We can do that by using IColumnsInfo...
CColumnsRowsetRowset *pColRowset = 0;
HRESULT hr = CreateRowset(
pUnkOuter,
riid,
cPropertySets,
rgPropertySets,
pColRowset,
ppColRowset);
if (SUCCEEDED(hr))
{
if (pColRowset)
{
T *pT = (T*)this;
CComQIPtr<IColumnsInfo> spColumnsInfo = pT->GetUnknown();
if (spColumnsInfo)
{
ULONG numCols = 0;
DBCOLUMNINFO *pColInfo = 0;
OLECHAR *pNotUsed = 0;
hr = spColumnsInfo->GetColumnInfo(&numCols, &pColInfo, &pNotUsed);
if (pNotUsed)
{
CoTaskMemFree(pNotUsed);
}
if (SUCCEEDED(hr))
{
hr = pColRowset->PopulateRowset(this, numCols, pColInfo);
}
CoTaskMemFree(pColInfo);
}
}
else
{
hr = E_UNEXPECTED;
}
}
return hr;
}
_bstr_t GetTableName()
{
return m_wsTableName;
}
void SetTableName( WCHAR* wsTableName )
{
m_wsTableName = wsTableName;
}
private :
HRESULT CreateRowset(
IUnknown * pUnkOuter,
REFIID riid,
ULONG cPropertySets,
DBPROPSET rgPropertySets[],
CColumnsRowsetRowset *&pRowsetObj,
IUnknown **ppRowset)
{
HRESULT hr;
T* pT = (T*)this;
if (ppRowset != NULL)
{
*ppRowset = NULL;
}
if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
{
return DB_E_NOAGGREGATION;
}
CComPolyObject<CColumnsRowsetRowset>* pPolyObj;
if (FAILED(hr = CComPolyObject<CColumnsRowsetRowset>::CreateInstance(pUnkOuter, &pPolyObj)))
{
return hr;
}
// Ref the created COM object and Auto release it on failure
CComPtr<IUnknown> spUnk;
hr = pPolyObj->QueryInterface(&spUnk);
if (FAILED(hr))
{
delete pPolyObj; // must hand delete as it is not ref'd
return hr;
}
// Get a pointer to the Rowset instance
pRowsetObj = &(pPolyObj->m_contained);
if (FAILED(hr = pRowsetObj->FInit(pT)))
{
return hr;
}
// Set Properties that were passed in.
const GUID* ppGuid[1];
ppGuid[0] = &DBPROPSET_ROWSET;
// Call SetProperties. The true in the last parameter indicates
// the special behavior that takes place on rowset creation (i.e.
// it succeeds as long as any of the properties were not marked
// as DBPROPS_REQUIRED.
hr = pRowsetObj->SetProperties(0, cPropertySets, rgPropertySets, 1, ppGuid, true);
if (FAILED(hr))
{
return hr;
}
pRowsetObj->SetSite(pT->GetUnknown());
if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL)
{
if (ppRowset != NULL)
*ppRowset = NULL;
return hr;
}
if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL)
{
if (ppRowset != NULL)
*ppRowset = NULL;
return hr;
}
hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
if (FAILED(hr))
return hr;
/* for (int iBind = 0; iBind < pT->m_rgBindings.GetSize(); iBind++)
{
T::_BindType* pBind = NULL;
T::_BindType* pBindSrc = NULL;
ATLTRY(pBind = new T::_BindType);
if (pBind == NULL)
{
ATLTRACE2(atlTraceDBProvider, 0, "Failed to allocate memory for new Binding\n");
return E_OUTOFMEMORY;
}
// auto cleanup on failure
CAutoMemRelease<T::_BindType> amr(pBind);
pBindSrc = pT->m_rgBindings.GetValueAt(iBind);
if (pBindSrc == NULL)
{
ATLTRACE2(atlTraceDBProvider, 0, "The map appears to be corrupted, failing!!\n");
return E_FAIL;
}
if (!pRowsetObj->m_rgBindings.Add(pT->m_rgBindings.GetKeyAt(iBind), pBind))
{
ATLTRACE2(atlTraceDBProvider, 0, "Failed to add hAccessor to Map\n");
return E_OUTOFMEMORY;
}
if (pBindSrc->cBindings)
{
ATLTRY(pBind->pBindings = new DBBINDING[pBindSrc->cBindings])
if (pBind->pBindings == NULL)
{
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Allocate dbbinding Array\n");
// We added it, must now remove on failure
pRowsetObj->m_rgBindings.Remove(pT->m_rgBindings.GetKeyAt(iBind));
return E_OUTOFMEMORY;
}
}
else
{
pBind->pBindings = NULL; // NULL Accessor
}
pBind->dwAccessorFlags = pBindSrc->dwAccessorFlags;
pBind->cBindings = pBindSrc->cBindings;
pBind->dwRef = 1;
memcpy (pBind->pBindings, pBindSrc->pBindings, (pBindSrc->cBindings)*sizeof(DBBINDING));
pBind = amr.Detach();
}
*/
return hr;
}
_bstr_t m_wsTableName;
};
#endif // __I_COLUMNS_ROWSET_IMPL__INCLUDED__