Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1288 lines
38 KiB

//---------------------------------------------------------------------------
// CursorMain.cpp : CursorMain implementation
//
// Copyright (c) 1996 Microsoft Corporation, All Rights Reserved
// Developed by Sheridan Software Systems, Inc.
//---------------------------------------------------------------------------
#include "stdafx.h"
#include "MSR2C.h"
#include "Notifier.h"
#include "RSColumn.h"
#include "RSSource.h"
#include "CursMain.h"
#include "ColUpdat.h"
#include "CursPos.h"
#include "CursBase.h"
#include "enumcnpt.h"
#include "Cursor.h"
#include "Bookmark.h"
#include "fastguid.h"
SZTHISFILE
#include "ARRAY_P.inl"
// static data
DWORD CVDCursorMain::s_dwMetaRefCount = 0;
ULONG CVDCursorMain::s_ulMetaColumns = 0;
CVDRowsetColumn * CVDCursorMain::s_rgMetaColumns = NULL;
//=--------------------------------------------------------------------------=
// CVDCursorMain - Constructor
//
CVDCursorMain::CVDCursorMain(LCID lcid) : m_resourceDLL(lcid)
{
m_fWeAddedMetaRef = FALSE;
m_fPassivated = FALSE;
m_fColumnsRowsetSupported = FALSE;
m_fInternalInsertRow = FALSE;
m_fInternalDeleteRows = FALSE;
m_fInternalSetData = FALSE;
m_fLiteralBookmarks = FALSE;
m_fOrderedBookmarks = FALSE;
m_fBookmarkSkipped = FALSE;
m_fConnected = FALSE;
m_dwAdviseCookie = 0;
m_ulColumns = 0;
m_rgColumns = NULL;
m_cbMaxBookmark = 0;
VDUpdateObjectCount(1); // update object count to prevent dll from being unloaded
#ifdef _DEBUG
g_cVDCursorMainCreated++;
#endif
}
//=--------------------------------------------------------------------------=
// ~CVDCursorMain - Destructor
//
CVDCursorMain::~CVDCursorMain()
{
Passivate();
VDUpdateObjectCount(-1); // update object count to allow dll to be unloaded
#ifdef _DEBUG
g_cVDCursorMainDestroyed++;
#endif
}
//=--------------------------------------------------------------------------=
// Pasivate when external ref count gets to zero
//
void CVDCursorMain::Passivate()
{
if (m_fPassivated)
return;
m_fPassivated = TRUE;
if (IsRowsetValid())
{
if (m_hAccessorBM)
GetAccessor()->ReleaseAccessor(m_hAccessorBM, NULL);
if (m_fConnected)
DisconnectIRowsetNotify();
}
DestroyColumns();
DestroyMetaColumns();
}
//=--------------------------------------------------------------------------=
// Create - Create cursor provider from row position or rowset
//=--------------------------------------------------------------------------=
// This function creates and initializes a new cursor main object
//
// Parameters:
// pRowPosition - [in] original IRowPosition provider (may be NULL)
// pRowset - [in] original IRowset provider
// ppCursor - [out] resulting ICursor provider
// lcid - [in] locale identifier
//
// Output:
// HRESULT - S_OK if successful
// E_INVALIDARG bad parameter
// E_OUTOFMEMORY not enough memory
// VD_E_CANNOTCONNECTIROWSETNOTIFY unable to connect IRowsetNotify
//
// Notes:
//
HRESULT CVDCursorMain::Create(IRowPosition* pRowPosition, IRowset * pRowset, ICursor ** ppCursor, LCID lcid)
{
ASSERT_POINTER(pRowset, IRowset)
ASSERT_POINTER(ppCursor, ICursor*)
if (!pRowset || !ppCursor)
return E_INVALIDARG;
// create new cursor main object
CVDCursorMain * pCursorMain = new CVDCursorMain(lcid);
if (!pCursorMain)
return E_OUTOFMEMORY;
// initialize rowset source
HRESULT hr = pCursorMain->Initialize(pRowset);
if (FAILED(hr))
{
pCursorMain->Release();
return hr;
}
// create array of column objects
hr = pCursorMain->CreateColumns();
if (FAILED(hr))
{
pCursorMain->Release();
return hr;
}
// create array of meta-column objects
hr = pCursorMain->CreateMetaColumns();
if (FAILED(hr))
{
pCursorMain->Release();
return hr;
}
// create bookmark accessor
DBBINDING rgBindings[1];
DBBINDSTATUS rgStatus[1];
memset(rgBindings, 0, sizeof(DBBINDING));
rgBindings[0].iOrdinal = 0;
rgBindings[0].obValue = 4;
rgBindings[0].obLength = 0;
rgBindings[0].dwPart = DBPART_VALUE | DBPART_LENGTH;
rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
rgBindings[0].cbMaxLen = pCursorMain->GetMaxBookmarkLen();
rgBindings[0].wType = DBTYPE_BYTES;
hr = pCursorMain->GetAccessor()->CreateAccessor(DBACCESSOR_ROWDATA,
1,
rgBindings,
0,
&pCursorMain->m_hAccessorBM,
rgStatus);
if (FAILED(hr))
{
pCursorMain->Release();
return VD_E_CANNOTCREATEBOOKMARKACCESSOR;
}
// create new cursor position object
CVDCursorPosition * pCursorPosition;
hr = CVDCursorPosition::Create(pRowPosition, pCursorMain, &pCursorPosition, &pCursorMain->m_resourceDLL);
if (FAILED(hr))
{
pCursorMain->Release();
return hr;
}
// create new cursor object
CVDCursor * pCursor;
hr = CVDCursor::Create(pCursorPosition, &pCursor, &pCursorMain->m_resourceDLL);
if (FAILED(hr))
{
((CVDNotifier*)pCursorPosition)->Release();
pCursorMain->Release();
return hr;
}
// connect IRowsetNotify
hr = pCursorMain->ConnectIRowsetNotify();
if (SUCCEEDED(hr))
pCursorMain->m_fConnected = TRUE;
// check rowset properties
BOOL fCanHoldRows = TRUE;
IRowsetInfo * pRowsetInfo = pCursorMain->GetRowsetInfo();
if (pRowsetInfo)
{
DBPROPID propids[] = { DBPROP_LITERALBOOKMARKS,
DBPROP_ORDEREDBOOKMARKS,
DBPROP_BOOKMARKSKIPPED,
DBPROP_CANHOLDROWS };
const DBPROPIDSET propsetids[] = { propids, 4, {0,0,0,0} };
memcpy((void*)&propsetids[0].guidPropertySet, &DBPROPSET_ROWSET, sizeof(DBPROPSET_ROWSET));
ULONG cPropertySets = 0;
DBPROPSET * propset = NULL;
hr = pRowsetInfo->GetProperties(1, propsetids, &cPropertySets, &propset);
if (SUCCEEDED(hr) && propset && propset->rgProperties)
{
if (DBPROPSTATUS_OK == propset->rgProperties[0].dwStatus)
pCursorMain->m_fLiteralBookmarks = V_BOOL(&propset->rgProperties[0].vValue);
if (DBPROPSTATUS_OK == propset->rgProperties[1].dwStatus)
pCursorMain->m_fOrderedBookmarks = V_BOOL(&propset->rgProperties[1].vValue);
if (DBPROPSTATUS_OK == propset->rgProperties[2].dwStatus)
pCursorMain->m_fBookmarkSkipped = V_BOOL(&propset->rgProperties[2].vValue);
if (DBPROPSTATUS_OK == propset->rgProperties[3].dwStatus)
fCanHoldRows = V_BOOL(&propset->rgProperties[3].vValue);
}
if (propset)
{
if (propset->rgProperties)
g_pMalloc->Free(propset->rgProperties);
g_pMalloc->Free(propset);
}
}
// release our references
pCursorMain->Release();
((CVDNotifier*)pCursorPosition)->Release();
// check for required property
if (!fCanHoldRows)
{
pCursor->Release();
return VD_E_REQUIREDPROPERTYNOTSUPPORTED;
}
// we're done
*ppCursor = pCursor;
return S_OK;
}
//=--------------------------------------------------------------------------=
// Create - Create cursor provider from rowset
//=--------------------------------------------------------------------------=
// This function creates and initializes a new cursor main object
//
// Parameters:
// pRowset - [in] original IRowset provider
// ppCursor - [out] resulting ICursor provider
// lcid - [in] locale identifier
//
// Output:
// HRESULT - S_OK if successful
// E_INVALIDARG bad parameter
// E_OUTOFMEMORY not enough memory
// VD_E_CANNOTCONNECTIROWSETNOTIFY unable to connect IRowsetNotify
//
// Notes:
//
HRESULT CVDCursorMain::Create(IRowset * pRowset, ICursor ** ppCursor, LCID lcid)
{
ASSERT_POINTER(pRowset, IRowset)
ASSERT_POINTER(ppCursor, ICursor*)
if (!pRowset || !ppCursor)
return E_INVALIDARG;
// create cursor as done before row position
return Create(NULL, pRowset, ppCursor, lcid);
}
//=--------------------------------------------------------------------------=
// Create - Create cursor provider from row position
//=--------------------------------------------------------------------------=
// This function creates and initializes a new cursor main object
//
// Parameters:
// pRowPosition - [in] original IRowPosition provider
// ppCursor - [out] resulting ICursor provider
// lcid - [in] locale identifier
//
// Output:
// HRESULT - S_OK if successful
// E_INVALIDARG bad parameter
// E_OUTOFMEMORY not enough memory
// VD_E_CANNOTCONNECTIROWSETNOTIFY unable to connect IRowPositionNotify
// VD_E_CANNOTGETROWSETINTERFACE unable to get IRowset
//
// Notes:
//
HRESULT CVDCursorMain::Create(IRowPosition * pRowPosition, ICursor ** ppCursor, LCID lcid)
{
ASSERT_POINTER(pRowPosition, IRowPosition)
ASSERT_POINTER(ppCursor, ICursor*)
if (!pRowPosition || !ppCursor)
return E_INVALIDARG;
IRowset * pRowset;
// get IRowset from IRowPosition
HRESULT hr = pRowPosition->GetRowset(IID_IRowset, (IUnknown**)&pRowset);
if (FAILED(hr))
return VD_E_CANNOTGETROWSETINTERFACE;
// create cursor with new row position parameter
hr = Create(pRowPosition, pRowset, ppCursor, lcid);
pRowset->Release();
// we're done
return hr;
}
typedef struct tagVDMETADATA_METADATA
{
const CURSOR_DBCOLUMNID * pCursorColumnID;
ULONG cbMaxLength;
CHAR * pszName;
DWORD dwCursorType;
} VDMETADATA_METADATA;
#define MAX_METADATA_COLUMNS 21
static const VDMETADATA_METADATA g_MetaDataMetaData[MAX_METADATA_COLUMNS] =
{
// Bookmark column
{ &CURSOR_COLUMN_BMKTEMPORARY, sizeof(ULONG), NULL, CURSOR_DBTYPE_BLOB },
// data columns
{ &CURSOR_COLUMN_COLUMNID, sizeof(CURSOR_DBCOLUMNID), "COLUMN_COLUMNID", CURSOR_DBTYPE_COLUMNID },
{ &CURSOR_COLUMN_DATACOLUMN, sizeof(VARIANT_BOOL), "COLUMN_DATACOLUMN", CURSOR_DBTYPE_BOOL },
{ &CURSOR_COLUMN_ENTRYIDMAXLENGTH, sizeof(ULONG), "COLUMN_ENTRYIDMAXLENGTH",CURSOR_DBTYPE_I4 },
{ &CURSOR_COLUMN_FIXED, sizeof(VARIANT_BOOL), "COLUMN_FIXED", CURSOR_DBTYPE_BOOL },
{ &CURSOR_COLUMN_MAXLENGTH, sizeof(ULONG), "COLUMN_MAXLENGTH", CURSOR_DBTYPE_I4 },
{ &CURSOR_COLUMN_NAME, 256, "COLUMN_NAME", VT_LPWSTR },
{ &CURSOR_COLUMN_NULLABLE, sizeof(VARIANT_BOOL), "COLUMN_NULLABLE", CURSOR_DBTYPE_BOOL },
{ &CURSOR_COLUMN_NUMBER, sizeof(ULONG), "COLUMN_NUMBER", CURSOR_DBTYPE_I4 },
{ &CURSOR_COLUMN_SCALE, sizeof(ULONG), "COLUMN_SCALE", CURSOR_DBTYPE_I4 },
{ &CURSOR_COLUMN_TYPE, sizeof(ULONG), "COLUMN_TYPE", CURSOR_DBTYPE_I4 },
{ &CURSOR_COLUMN_UPDATABLE, sizeof(ULONG), "COLUMN_UPDATABLE", CURSOR_DBTYPE_I4 },
{ &CURSOR_COLUMN_BINDTYPE, sizeof(ULONG), "COLUMN_BINDTYPE", CURSOR_DBTYPE_I4 },
// optional metadata columns - supported with IColumnsRowset only)
{ &CURSOR_COLUMN_AUTOINCREMENT, sizeof(VARIANT_BOOL), "COLUMN_AUTOINCREMENT", CURSOR_DBTYPE_BOOL },
{ &CURSOR_COLUMN_BASECOLUMNNAME, 256, "COLUMN_BASECOLUMNNAME",VT_LPWSTR },
{ &CURSOR_COLUMN_BASENAME, 256, "COLUMN_BASENAME", VT_LPWSTR },
{ &CURSOR_COLUMN_COLLATINGORDER, sizeof(LCID), "COLUMN_COLLATINGORDER",CURSOR_DBTYPE_I4 },
{ &CURSOR_COLUMN_DEFAULTVALUE, 256, "COLUMN_DEFAULTVALUE", VT_LPWSTR },
{ &CURSOR_COLUMN_HASDEFAULT, sizeof(VARIANT_BOOL), "COLUMN_HASDEFAULT", CURSOR_DBTYPE_BOOL },
{ &CURSOR_COLUMN_CASESENSITIVE, sizeof(VARIANT_BOOL), "COLUMN_CASESENSITIVE", CURSOR_DBTYPE_BOOL },
{ &CURSOR_COLUMN_UNIQUE, sizeof(VARIANT_BOOL), "COLUMN_UNIQUE", CURSOR_DBTYPE_BOOL },
};
//=--------------------------------------------------------------------------=
// CreateMetaColumns - Create array of meta-column objects
//
HRESULT CVDCursorMain::CreateMetaColumns()
{
HRESULT hr = S_OK;
EnterCriticalSection(&g_CriticalSection);
if (!s_dwMetaRefCount)
{
// allocate a static aray of metadata metadata columns
s_rgMetaColumns = new CVDRowsetColumn[MAX_METADATA_COLUMNS];
if (!s_rgMetaColumns)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
s_ulMetaColumns = MAX_METADATA_COLUMNS; // number of columns for IColumnsInfo
// initialize the array elments from the static g_MetaDataMetaData table
for (int i = 0; i < MAX_METADATA_COLUMNS; i++)
{
s_rgMetaColumns[i].Initialize(g_MetaDataMetaData[i].pCursorColumnID,
(BOOL)i, // false for 1st column (bookmark) TRUE for all other columns
g_MetaDataMetaData[i].cbMaxLength,
g_MetaDataMetaData[i].pszName,
g_MetaDataMetaData[i].dwCursorType,
i ); // ordinal number
}
}
s_dwMetaRefCount++;
m_fWeAddedMetaRef = TRUE;
cleanup:
LeaveCriticalSection(&g_CriticalSection);
return hr;
}
//=--------------------------------------------------------------------------=
// DestroyMetaColumns - Destroy array of meta-columns objects
//
void CVDCursorMain::DestroyMetaColumns()
{
EnterCriticalSection(&g_CriticalSection);
if (m_fWeAddedMetaRef)
{
s_dwMetaRefCount--;
if (!s_dwMetaRefCount)
{
delete [] s_rgMetaColumns;
s_ulMetaColumns = 0;
s_rgMetaColumns = NULL;
}
}
LeaveCriticalSection(&g_CriticalSection);
}
//=--------------------------------------------------------------------------=
// CreateColumns - Create array of column objects
//
HRESULT CVDCursorMain::CreateColumns()
{
IColumnsInfo * pColumnsInfo;
// try to get IRowset's simple metadata interface
HRESULT hr = m_pRowset->QueryInterface(IID_IColumnsInfo, (void**)&pColumnsInfo);
if (FAILED(hr))
return VD_E_CANNOTGETMANDATORYINTERFACE;
ULONG cColumns = 0;
DBCOLUMNINFO * pInfo = NULL;
WCHAR * pStringsBuffer = NULL;
// now get column information
hr = pColumnsInfo->GetColumnInfo(&cColumns, &pInfo, &pStringsBuffer);
if (FAILED(hr))
{
pColumnsInfo->Release();
return VD_E_CANNOTGETCOLUMNINFO;
}
// store column count
// note cColumns includes the bookmark column (0)
m_ulColumns = cColumns;
// add one for CURSOR_COLUMN_BMK_CURSOR
m_ulColumns++;
// if rowset supports DBPROP_BOOKMARKSKIPPED add two for
// CURSOR_COLUMN_BMK_TEMPORARYREL and CURSOR_COLUMN_BMK_CURSORREL
if (m_fBookmarkSkipped)
m_ulColumns += 2;
// create array of rowset column objects
m_rgColumns = new CVDRowsetColumn[m_ulColumns];
if (!m_rgColumns)
{
if (pInfo)
g_pMalloc->Free(pInfo);
if (pStringsBuffer)
g_pMalloc->Free(pStringsBuffer);
pColumnsInfo->Release();
return E_OUTOFMEMORY;
}
ULONG ulCursorOrdinal = 0;
// get maximum length of bookmarks
m_cbMaxBookmark = pInfo[0].ulColumnSize;
// initialize data column(s)
for (ULONG ulCol = 1; ulCol < cColumns; ulCol++)
{
m_rgColumns[ulCursorOrdinal].Initialize(ulCol, ulCursorOrdinal, &pInfo[ulCol], m_cbMaxBookmark);
ulCursorOrdinal++;
}
// initialize bookmark columns
pInfo[0].pwszName = NULL; // ICursor requires bookmark columns have a NULL name
m_rgColumns[ulCursorOrdinal].Initialize(0, ulCursorOrdinal, &pInfo[0], m_cbMaxBookmark,
(CURSOR_DBCOLUMNID*)&CURSOR_COLUMN_BMKTEMPORARY);
ulCursorOrdinal++;
m_rgColumns[ulCursorOrdinal].Initialize(0, ulCursorOrdinal, &pInfo[0], m_cbMaxBookmark,
(CURSOR_DBCOLUMNID*)&CURSOR_COLUMN_BMKCURSOR);
ulCursorOrdinal++;
if (m_fBookmarkSkipped)
{
m_rgColumns[ulCursorOrdinal].Initialize(0, ulCursorOrdinal, &pInfo[0], m_cbMaxBookmark,
(CURSOR_DBCOLUMNID*)&CURSOR_COLUMN_BMKTEMPORARYREL);
ulCursorOrdinal++;
m_rgColumns[ulCursorOrdinal].Initialize(0, ulCursorOrdinal, &pInfo[0], m_cbMaxBookmark,
(CURSOR_DBCOLUMNID*)&CURSOR_COLUMN_BMKCURSORREL);
ulCursorOrdinal++;
}
// free resources
if (pInfo)
g_pMalloc->Free(pInfo);
if (pStringsBuffer)
g_pMalloc->Free(pStringsBuffer);
pColumnsInfo->Release();
InitOptionalMetadata(cColumns);
return S_OK;
}
//=--------------------------------------------------------------------------=
// InitOptionalMetadata - gets additional metadata from IColumnsRowset (if available)
//
void CVDCursorMain::InitOptionalMetadata(ULONG cColumns)
{
// we should return if there is only a bookmark column
if (cColumns < 2)
return;
IColumnsRowset * pColumnsRowset = NULL;
// try to get IColumnsRowset interface
HRESULT hr = m_pRowset->QueryInterface(IID_IColumnsRowset, (void**)&pColumnsRowset);
if (FAILED(hr))
return;
IRowset * pRowset = NULL;
IColumnsInfo * pColumnsInfo = NULL;
IAccessor * pAccessor = NULL;
ULONG cOptColumnsAvailable = 0;
DBID * rgOptColumnsAvailable = NULL;
DBID * pOptColumnsAvailable = NULL; // work ptr
ULONG cOptColumns = 0;
DBID * rgOptColumns = NULL;
DBID * pOptColumns = NULL; //work ptr
ULONG ulBuffLen = 0;
BYTE * pBuff = NULL;
HACCESSOR hAccessor;
BOOL fAccessorCreated = FALSE;
HROW * rgRows = NULL;
ULONG cRowsObtained = 0;
// we are only interested in a few of the optional columns
ULONG rgColumnPropids[VD_COLUMNSROWSET_MAX_OPT_COLUMNS];
ULONG rgOrdinals[VD_COLUMNSROWSET_MAX_OPT_COLUMNS];
DBBINDING rgBindings[VD_COLUMNSROWSET_MAX_OPT_COLUMNS];
DBBINDING * pBinding = NULL; // work ptr
BOOL fMatched;
GUID guidCID = DBCIDGUID;
ULONG cColumnsMatched = 0;
ULONG i, j;
// get array of available columns
hr = pColumnsRowset->GetAvailableColumns(&cOptColumnsAvailable, &rgOptColumnsAvailable);
if (FAILED(hr) || 0 == cOptColumnsAvailable)
goto cleanup;
ASSERT_(rgOptColumnsAvailable);
// allocate enough DBIDs for the lesser of the total available columns or the total number of
// columns we're interested in
rgOptColumns = (DBID *)g_pMalloc->Alloc(min(cOptColumnsAvailable, VD_COLUMNSROWSET_MAX_OPT_COLUMNS)
* sizeof(DBID));
if (!rgOptColumns)
goto cleanup;
// initalize work pointers
pOptColumnsAvailable = rgOptColumnsAvailable;
pOptColumns = rgOptColumns;
pBinding = rgBindings;
memset(pBinding, 0, sizeof(DBBINDING) * VD_COLUMNSROWSET_MAX_OPT_COLUMNS);
// search available columns for the ones we are interested in copying them into rgOptColumns
for (i = 0; i < cOptColumnsAvailable && cColumnsMatched < VD_COLUMNSROWSET_MAX_OPT_COLUMNS; i++)
{
fMatched = FALSE; // initialize to false
if (DBKIND_GUID_PROPID == pOptColumnsAvailable->eKind &&
DO_GUIDS_MATCH(pOptColumnsAvailable->uGuid.guid, guidCID))
{
switch (pOptColumnsAvailable->uName.ulPropid)
{
case 12: //DBCOLUMN_COLLATINGSEQUENCE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)12};
pBinding->obValue = ulBuffLen;
ulBuffLen += sizeof(ULONG);
pBinding->obStatus = ulBuffLen;
ulBuffLen += sizeof(DBSTATUS);
pBinding->dwPart = DBPART_VALUE | DBPART_STATUS;
pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
pBinding->wType = DBTYPE_I4;
fMatched = TRUE;
break;
//string properties
case 10: //DBCOLUMN_BASECOLUMNNAME = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)10};
case 11: //DBCOLUMN_BASETABLENAME = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)11};
case 14: //DBCOLUMN_DEFAULTVALUE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)14};
pBinding->obValue = ulBuffLen;
ulBuffLen += 512;
pBinding->obLength = ulBuffLen;
ulBuffLen += sizeof(ULONG);
pBinding->obStatus = ulBuffLen;
ulBuffLen += sizeof(DBSTATUS);
pBinding->dwPart = DBPART_VALUE | DBPART_LENGTH |DBPART_STATUS;
pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
pBinding->cbMaxLen = 512;
pBinding->wType = DBTYPE_WSTR;
fMatched = TRUE;
break;
// bool properties
case 16: //DBCOLUMN_HASDEFAULT = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)16};
case 17: //DBCOLUMN_ISAUTOINCREMENT = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)17};
case 18: //DBCOLUMN_ISCASESENSITIVE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)18};
case 21: //DBCOLUMN_ISUNIQUE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)21};
pBinding->obValue = ulBuffLen;
ulBuffLen += sizeof(VARIANT_BOOL);
pBinding->obStatus = ulBuffLen;
ulBuffLen += sizeof(DBSTATUS);
pBinding->dwPart = DBPART_VALUE | DBPART_STATUS;
pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
pBinding->wType = DBTYPE_BOOL;
fMatched = TRUE;
break;
}
}
if (fMatched)
{
rgColumnPropids[cColumnsMatched] = pOptColumnsAvailable->uName.ulPropid;
*pOptColumns = *pOptColumnsAvailable;
pBinding++;
pOptColumns++;
cColumnsMatched++;
}
pOptColumnsAvailable++;
}
if (!cColumnsMatched)
goto cleanup;
// get column's rowset
hr = pColumnsRowset->GetColumnsRowset(NULL,
cColumnsMatched,
rgOptColumns,
IID_IRowset,
0,
NULL,
(IUnknown**)&pRowset);
if FAILED(hr)
{
ASSERT_(FALSE);
goto cleanup;
}
// get IColumnsInfo interface on column's rowset
hr = pRowset->QueryInterface(IID_IColumnsInfo, (void**)&pColumnsInfo);
if (FAILED(hr))
{
ASSERT_(FALSE);
goto cleanup;
}
// get ordinals for our optional columns
hr = pColumnsInfo->MapColumnIDs(cColumnsMatched, rgOptColumns, rgOrdinals);
if (S_OK != hr)
{
ASSERT_(FALSE);
goto cleanup;
}
// update binding structures with ordinals
for (i = 0; i < cColumnsMatched; i++)
rgBindings[i].iOrdinal = rgOrdinals[i];
// get IAccessor interface on column's rowset
hr = pRowset->QueryInterface(IID_IAccessor, (void**)&pAccessor);
if (FAILED(hr))
{
ASSERT_(FALSE);
goto cleanup;
}
// create accessor based on rgBindings array
hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
cColumnsMatched,
rgBindings,
ulBuffLen,
&hAccessor,
NULL);
if (S_OK != hr)
{
ASSERT_(FALSE);
goto cleanup;
}
// set flag that accessor was successfully created (used during cleanup)
fAccessorCreated = TRUE;
// allocate a buffer to hold the metadata
pBuff = (BYTE *)g_pMalloc->Alloc(ulBuffLen);
if (!pBuff)
{
ASSERT_(FALSE);
goto cleanup;
}
// get all rows (each row represents a column in the original rowset)
// except the first row which represents the bookmark column
hr = pRowset->GetNextRows(0, // reserved
1, // skip the bookmark row
cColumns - 1, // get 1 less than cColumns to account for bookmark row
&cRowsObtained, // return count of rows obtanied
&rgRows);
if (FAILED(hr) || !cRowsObtained)
{
ASSERT_(FALSE);
goto cleanup;
}
BYTE * pValue;
// loop through all rows obtained
for (i = 0; i < cRowsObtained; i++)
{
// call GetData to get the metadata for this row (which represents a column in the orig rowset)
hr = pRowset->GetData(rgRows[i], hAccessor, pBuff);
if SUCCEEDED(hr)
{
// now update the CVDRowsetColumn object (that this row represents)
// with the values returned from GetData
for (j = 0; j < cColumnsMatched; j++)
{
if (DBBINDSTATUS_OK != *(DBSTATUS*)(pBuff + rgBindings[j].obStatus))
continue;
// set pValue to point into buffer at correct offset
pValue = pBuff + rgBindings[j].obValue;
switch (rgColumnPropids[j])
{
case 12: //DBCOLUMN_COLLATINGSEQUENCE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)12};
m_rgColumns[i].SetCollatingOrder(*(LCID*)pValue);
break;
//string properties
case 10: //DBCOLUMN_BASECOLUMNNAME = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)10};
m_rgColumns[i].SetBaseColumnName((WCHAR*)pValue, *(ULONG*)(pBuff + rgBindings[j].obLength));
break;
case 11: //DBCOLUMN_BASETABLENAME = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)11};
m_rgColumns[i].SetBaseName((WCHAR*)pValue, *(ULONG*)(pBuff + rgBindings[j].obLength));
break;
case 14: //DBCOLUMN_DEFAULTVALUE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)14};
m_rgColumns[i].SetDefaultValue((WCHAR*)pValue, *(ULONG*)(pBuff + rgBindings[j].obLength));
break;
// bool properties
case 16: //DBCOLUMN_HASDEFAULT = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)16};
m_rgColumns[i].SetHasDefault(*(VARIANT_BOOL*)pValue);
break;
case 17: //DBCOLUMN_ISAUTOINCREMENT = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)17};
m_rgColumns[i].SetAutoIncrement(*(VARIANT_BOOL*)pValue);
break;
case 18: //DBCOLUMN_ISCASESENSITIVE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)18};
m_rgColumns[i].SetCaseSensitive(*(VARIANT_BOOL*)pValue);
break;
case 21: //DBCOLUMN_ISUNIQUE = {DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)21};
m_rgColumns[i].SetUnique(*(VARIANT_BOOL*)pValue);
break;
default:
ASSERT_(FALSE);
break;
}
}
}
else
ASSERT_(FALSE);
}
m_fColumnsRowsetSupported = TRUE;
cleanup:
if (pBuff)
g_pMalloc->Free(pBuff);
if (pAccessor)
{
if (fAccessorCreated)
pAccessor->ReleaseAccessor(hAccessor, NULL);
pAccessor->Release();
}
if (pRowset)
{
if (cRowsObtained)
{
pRowset->ReleaseRows(cRowsObtained, rgRows, NULL, NULL, NULL);
ASSERT_(rgRows);
g_pMalloc->Free(rgRows);
}
pRowset->Release();
}
if (pColumnsInfo)
pColumnsInfo->Release();
if (rgOptColumnsAvailable)
g_pMalloc->Free(rgOptColumnsAvailable);
if (rgOptColumns)
g_pMalloc->Free(rgOptColumns);
if (pColumnsRowset)
pColumnsRowset->Release();
}
//=--------------------------------------------------------------------------=
// DestroyColumns - Destroy array of column objects
//
void CVDCursorMain::DestroyColumns()
{
delete [] m_rgColumns;
m_ulColumns = 0;
m_rgColumns = NULL;
}
//=--------------------------------------------------------------------------=
// ConnectIRowsetNotify - Connect IRowsetNotify interface
//
HRESULT CVDCursorMain::ConnectIRowsetNotify()
{
IConnectionPointContainer * pConnectionPointContainer;
HRESULT hr = GetRowset()->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
if (FAILED(hr))
return VD_E_CANNOTCONNECTIROWSETNOTIFY;
IConnectionPoint * pConnectionPoint;
hr = pConnectionPointContainer->FindConnectionPoint(IID_IRowsetNotify, &pConnectionPoint);
if (FAILED(hr))
{
pConnectionPointContainer->Release();
return VD_E_CANNOTCONNECTIROWSETNOTIFY;
}
hr = pConnectionPoint->Advise(&m_RowsetNotify, &m_dwAdviseCookie);
pConnectionPointContainer->Release();
pConnectionPoint->Release();
return hr;
}
//=--------------------------------------------------------------------------=
// DisconnectIRowsetNotify - Disconnect IRowsetNotify interface
//
void CVDCursorMain::DisconnectIRowsetNotify()
{
IConnectionPointContainer * pConnectionPointContainer;
HRESULT hr = GetRowset()->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
if (FAILED(hr))
return;
IConnectionPoint * pConnectionPoint;
hr = pConnectionPointContainer->FindConnectionPoint(IID_IRowsetNotify, &pConnectionPoint);
if (FAILED(hr))
{
pConnectionPointContainer->Release();
return;
}
hr = pConnectionPoint->Unadvise(m_dwAdviseCookie);
if (SUCCEEDED(hr))
m_dwAdviseCookie = 0; // clear connection point identifier
pConnectionPointContainer->Release();
pConnectionPoint->Release();
}
//=--------------------------------------------------------------------------=
// IUnknown QueryInterface
//
HRESULT CVDCursorMain::QueryInterface(REFIID riid, void **ppvObjOut)
{
ASSERT_POINTER(ppvObjOut, IUnknown*)
if (!ppvObjOut)
return E_INVALIDARG;
*ppvObjOut = NULL;
if (DO_GUIDS_MATCH(riid, IID_IUnknown))
{
*ppvObjOut = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
//=--------------------------------------------------------------------------=
// IUnknown AddRef (needed to resolve ambiguity)
//
ULONG CVDCursorMain::AddRef(void)
{
return CVDNotifier::AddRef();
}
//=--------------------------------------------------------------------------=
// IUnknown Release (needed to resolve ambiguity)
//
ULONG CVDCursorMain::Release(void)
{
if (1 == m_dwRefCount)
Passivate(); // unhook everything including notification sink
if (1 > --m_dwRefCount)
{
if (0 == m_RowsetNotify.GetRefCount())
delete this;
return 0;
}
return m_dwRefCount;
}
//=--------------------------------------------------------------------------=
// IsSameRowAsNew - Determine if specified hRow is an addrow
//
BOOL CVDCursorMain::IsSameRowAsNew(HROW hrow)
{
for (int k = 0; k < m_Children.GetSize(); k++)
{
if (((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->IsSameRowAsNew(hrow) == S_OK)
return TRUE;
}
return FALSE;
}
//=--------------------------------------------------------------------------=
// AddedRows - Get the number of add-rows in cursor
//
ULONG CVDCursorMain::AddedRows()
{
ULONG cAdded = 0;
for (int k = 0; k < m_Children.GetSize(); k++)
{
if (((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->GetEditMode() == CURSOR_DBEDITMODE_ADD)
cAdded++;
}
return cAdded;
}
//=--------------------------------------------------------------------------=
// IRowsetNotify Methods
//=--------------------------------------------------------------------------=
//=--------------------------------------------------------------------------=
// IRowsetNotify OnFieldChange
//=--------------------------------------------------------------------------=
// Forward to all CVDCursorPosition objects in our family
//
HRESULT CVDCursorMain::OnFieldChange(IRowset *pRowset,
HROW hRow,
ULONG cColumns,
ULONG rgColumns[],
DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny)
{
HRESULT hr = S_OK;
// return if notification caused by internal rowset call
if (m_fInternalSetData && eReason == DBREASON_COLUMN_SET)
return hr;
for (int k = 0; k < m_Children.GetSize(); k++)
{
hr = ((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->OnFieldChange(pRowset,
hRow,
cColumns,
rgColumns,
eReason,
ePhase,
fCantDeny);
if (hr)
break;
}
return hr;
}
//=--------------------------------------------------------------------------=
// IRowsetNotify OnRowChange
//=--------------------------------------------------------------------------=
// Forward to all CVDCursorPosition objects in our family
//
HRESULT CVDCursorMain::OnRowChange(IRowset *pRowset,
ULONG cRows,
const HROW rghRows[],
DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny)
{
HRESULT hr = S_OK;
// return if notification caused by internal rowset call (either insert or delete)
if (m_fInternalInsertRow && eReason == DBREASON_ROW_INSERT || m_fInternalDeleteRows && eReason == DBREASON_ROW_DELETE)
return hr;
for (int k = 0; k < m_Children.GetSize(); k++)
{
hr = ((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->OnRowChange(pRowset,
cRows,
rghRows,
eReason,
ePhase,
fCantDeny);
if (hr)
break;
}
return hr;
}
//=--------------------------------------------------------------------------=
// IRowsetNotify OnRowsetChange
//=--------------------------------------------------------------------------=
// Forward to all CVDCursorPosition objects in our family
//
HRESULT CVDCursorMain::OnRowsetChange(IRowset *pRowset,
DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny)
{
HRESULT hr = S_OK;
for (int k = 0; k < m_Children.GetSize(); k++)
{
hr = ((CVDCursorPosition*)(CVDNotifier*)m_Children[k])->OnRowsetChange(pRowset,
eReason,
ePhase,
fCantDeny);
if (hr)
break;
}
return hr;
}
//=--------------------------------------------------------------------------=
// CVDCursorMain::CVDRowsetNotify::m_pMainUnknown
//=--------------------------------------------------------------------------=
// this method is used when we're sitting in the private unknown object,
// and we need to get at the pointer for the main unknown. basically, it's
// a little better to do this pointer arithmetic than have to store a pointer
// to the parent, etc.
//
inline CVDCursorMain *CVDCursorMain::CVDRowsetNotify::m_pMainUnknown
(
void
)
{
return (CVDCursorMain *)((LPBYTE)this - offsetof(CVDCursorMain, m_RowsetNotify));
}
//=--------------------------------------------------------------------------=
// CVDCursorMain::CVDRowsetNotify::QueryInterface
//=--------------------------------------------------------------------------=
// this is the non-delegating internal QI routine.
//
// Parameters:
// REFIID - [in] interface they want
// void ** - [out] where they want to put the resulting object ptr.
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE
//
// Notes:
//
STDMETHODIMP CVDCursorMain::CVDRowsetNotify::QueryInterface
(
REFIID riid,
void **ppvObjOut
)
{
if (!ppvObjOut)
return E_INVALIDARG;
*ppvObjOut = NULL;
if (DO_GUIDS_MATCH(riid, IID_IUnknown))
*ppvObjOut = (IUnknown *)this;
else
if (DO_GUIDS_MATCH(riid, IID_IRowsetNotify))
*ppvObjOut = (IUnknown *)this;
if (*ppvObjOut)
{
m_cRef++;
return S_OK;
}
return E_NOINTERFACE;
}
//=--------------------------------------------------------------------------=
// CVDCursorMain::CVDRowsetNotify::AddRef
//=--------------------------------------------------------------------------=
// adds a tick to the current reference count.
//
// Output:
// ULONG - the new reference count
//
// Notes:
//
ULONG CVDCursorMain::CVDRowsetNotify::AddRef
(
void
)
{
return ++m_cRef;
}
//=--------------------------------------------------------------------------=
// CVDCursorMain::CVDRowsetNotify::Release
//=--------------------------------------------------------------------------=
// removes a tick from the count, and delets the object if necessary
//
// Output:
// ULONG - remaining refs
//
// Notes:
//
ULONG CVDCursorMain::CVDRowsetNotify::Release
(
void
)
{
ULONG cRef = --m_cRef;
if (!m_cRef && !m_pMainUnknown()->m_dwRefCount)
delete m_pMainUnknown();
return cRef;
}
//=--------------------------------------------------------------------------=
// IRowsetNotify Methods
//=--------------------------------------------------------------------------=
//=--------------------------------------------------------------------------=
// IRowsetNotify OnFieldChange
//=--------------------------------------------------------------------------=
// Forward to all CVDCursorPosition objects in our family
//
HRESULT CVDCursorMain::CVDRowsetNotify::OnFieldChange(IRowset *pRowset,
HROW hRow,
ULONG cColumns,
ULONG rgColumns[],
DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny)
{
return m_pMainUnknown()->OnFieldChange(pRowset,
hRow,
cColumns,
rgColumns,
eReason,
ePhase,
fCantDeny);
}
//=--------------------------------------------------------------------------=
// IRowsetNotify OnRowChange
//=--------------------------------------------------------------------------=
// Forward to all CVDCursorPosition objects in our family
//
HRESULT CVDCursorMain::CVDRowsetNotify::OnRowChange(IRowset *pRowset,
ULONG cRows,
const HROW rghRows[],
DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny)
{
return m_pMainUnknown()->OnRowChange(pRowset,
cRows,
rghRows,
eReason,
ePhase,
fCantDeny);
}
//=--------------------------------------------------------------------------=
// IRowsetNotify OnRowsetChange
//=--------------------------------------------------------------------------=
// Forward to all CVDCursorPosition objects in our family
//
HRESULT CVDCursorMain::CVDRowsetNotify::OnRowsetChange(IRowset *pRowset,
DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny)
{
return m_pMainUnknown()->OnRowsetChange(pRowset,
eReason,
ePhase,
fCantDeny);
}