1352 lines
43 KiB
C++
1352 lines
43 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1994 - 2000.
|
||
|
//
|
||
|
// File: colinfo.cxx
|
||
|
//
|
||
|
// Contents: Column information for rowsets
|
||
|
//
|
||
|
// Classes: CColumnsInfo
|
||
|
//
|
||
|
// Notes: Designed as an aggregated class of an IRowset or an
|
||
|
// IQuery implementation.
|
||
|
//
|
||
|
// History: 04 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.cxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <colinfo.hxx>
|
||
|
#include <query.hxx>
|
||
|
#include <tblvarnt.hxx>
|
||
|
|
||
|
#include "tblrowal.hxx"
|
||
|
#include "tabledbg.hxx"
|
||
|
|
||
|
// Always bind as DBTYPE_VARIANT, so we can use provider-owned memory
|
||
|
|
||
|
#define ALWAYS_USE_VARIANT_BINDING
|
||
|
|
||
|
ULONG CColumnsInfo::_nUnique = 0;
|
||
|
|
||
|
const static GUID guidBmk = DBBMKGUID;
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CColumnsInfo::QueryInterface, public
|
||
|
//
|
||
|
// Synopsis: Invokes QueryInterface on controlling unknown object
|
||
|
//
|
||
|
// Arguments: [riid] -- interface ID
|
||
|
// [ppvObject] -- returned interface pointer
|
||
|
//
|
||
|
// Returns: SCODE
|
||
|
//
|
||
|
// History: 04 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP CColumnsInfo::QueryInterface(
|
||
|
REFIID riid,
|
||
|
void **ppvObject)
|
||
|
{
|
||
|
return _rUnknown.QueryInterface(riid,ppvObject);
|
||
|
} //QueryInterface
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CColumnsInfo::AddRef, public
|
||
|
//
|
||
|
// Synopsis: Invokes AddRef on controlling unknown object
|
||
|
//
|
||
|
// Returns: ULONG
|
||
|
//
|
||
|
// History: 04 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CColumnsInfo::AddRef()
|
||
|
{
|
||
|
return _rUnknown.AddRef();
|
||
|
} //AddRef
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CColumnsInfo::Release, public
|
||
|
//
|
||
|
// Synopsis: Invokes Release on controlling unknown object
|
||
|
//
|
||
|
// Returns: ULONG
|
||
|
//
|
||
|
// History: 04 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CColumnsInfo::Release()
|
||
|
{
|
||
|
return _rUnknown.Release();
|
||
|
} //Release
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::CColumnsInfo, public
|
||
|
//
|
||
|
// Synopsis: Creates a column information class
|
||
|
//
|
||
|
// Arguments: [cols] -- a reference to the output column set, pidmapped
|
||
|
// [pidmap] -- property IDs and names for the columns
|
||
|
// [ErrorObject] -- a reference to enclosing object's error obj.
|
||
|
// [rUnknown] -- a reference to the controlling IUnknown
|
||
|
// [fSequential] -- TRUE if the query is sequential
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// History: 04 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CColumnsInfo::CColumnsInfo(
|
||
|
CColumnSet const & cols,
|
||
|
CPidMapperWithNames const & pidmap,
|
||
|
CCIOleDBError & ErrorObject,
|
||
|
IUnknown & rUnknown,
|
||
|
BOOL fSequential ) :
|
||
|
_idUnique(0),
|
||
|
_rUnknown(rUnknown),
|
||
|
_fSequential(fSequential),
|
||
|
_fChaptered(FALSE),
|
||
|
_cbRowWidth(0),
|
||
|
_cColumns( cols.Count() ),
|
||
|
_cBoundColumns(0),
|
||
|
_iColRowId(pidInvalid),
|
||
|
_pColumns(0),
|
||
|
_pidmap( cols.Count()+1 ),
|
||
|
_ErrorObject( ErrorObject ),
|
||
|
_fNotPrepared(FALSE)
|
||
|
{
|
||
|
_SetColumns(cols, pidmap, fSequential);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::CColumnsInfo, public
|
||
|
//
|
||
|
// Synopsis: Creates an empty column information class
|
||
|
//
|
||
|
// Arguments: [rUnknown] -- a reference to the controlling IUnknown
|
||
|
// [ErrorObject] -- a reference to enclosing object's error obj.
|
||
|
//
|
||
|
// Notes: Used in the command object where column information may
|
||
|
// change, depending upon the command.
|
||
|
//
|
||
|
// History: 11 Aug 1997 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CColumnsInfo::CColumnsInfo(
|
||
|
IUnknown & rUnknown,
|
||
|
CCIOleDBError & ErrorObject,
|
||
|
BOOL fNotPrepared) :
|
||
|
_idUnique(_GetNewId()),
|
||
|
_rUnknown(rUnknown),
|
||
|
_fSequential(FALSE),
|
||
|
_fChaptered(FALSE),
|
||
|
_cbRowWidth(0),
|
||
|
_cColumns( 0 ),
|
||
|
_cBoundColumns(0),
|
||
|
_iColRowId(pidInvalid),
|
||
|
_pColumns(0),
|
||
|
_pidmap( 0 ),
|
||
|
_ErrorObject( ErrorObject ),
|
||
|
_fNotPrepared(fNotPrepared)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::~CColumnsInfo, public
|
||
|
//
|
||
|
// Synopsis: Destroys a column information class
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// History: 12 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CColumnsInfo::~CColumnsInfo( )
|
||
|
{
|
||
|
delete _pColumns;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::InitColumns, public
|
||
|
//
|
||
|
// Synopsis: Initializes or reinitializes columns.
|
||
|
//
|
||
|
// Arguments: [cols] -- a reference to the output column set, pidmapped
|
||
|
// [pidmap] -- property IDs and names for the columns
|
||
|
// [fSequential] -- TRUE if the query is sequential
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// History: 11 Aug 1997 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CColumnsInfo::InitColumns (
|
||
|
CColumnSet const & cols,
|
||
|
CPidMapperWithNames const & pidmap,
|
||
|
BOOL fSequential )
|
||
|
{
|
||
|
_pidmap.Clear();
|
||
|
_cColumns = cols.Count();
|
||
|
_fSequential = fSequential;
|
||
|
_SetColumns(cols, pidmap, fSequential);
|
||
|
_fChaptered = FALSE;
|
||
|
_fNotPrepared = FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::InitColumns, public
|
||
|
//
|
||
|
// Synopsis: Reinitializes columns to be null.
|
||
|
//
|
||
|
// Arguments: [fNotPrepared] - TRUE if GetColumnInfo and MapColumnIDs should
|
||
|
// return DB_E_NOTPREPARED for a command object
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// History: 11 Aug 1997 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CColumnsInfo::InitColumns ( BOOL fNotPrepared )
|
||
|
{
|
||
|
_pidmap.Clear();
|
||
|
_cColumns = 0;
|
||
|
_fSequential = FALSE;
|
||
|
_fChaptered = FALSE;
|
||
|
_fNotPrepared = fNotPrepared;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::_SetColumns, private
|
||
|
//
|
||
|
// Synopsis: Initializes or reinitializes columns.
|
||
|
//
|
||
|
// Arguments: [cols] -- a reference to the output column set, pidmapped
|
||
|
// [pidmap] -- property IDs and names for the columns
|
||
|
// [fSequential] -- TRUE if the query is sequential
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// History: 11 Aug 1997 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CColumnsInfo::_SetColumns (
|
||
|
CColumnSet const & cols,
|
||
|
CPidMapperWithNames const & pidmap,
|
||
|
BOOL fSequential )
|
||
|
{
|
||
|
Win4Assert( 0 == _pColumns && 0 == _cbRowWidth );
|
||
|
_idUnique = _GetNewId();
|
||
|
|
||
|
//
|
||
|
// We want the PidMapper to give back 1-based column numbers;
|
||
|
// add either a null propspec or the bookmark column as its first element.
|
||
|
//
|
||
|
|
||
|
if (fSequential)
|
||
|
{
|
||
|
CFullPropSpec nullCol;
|
||
|
_pidmap.NameToPid( nullCol );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CFullPropSpec bmkCol( guidBmk, PROPID_DBBMK_BOOKMARK );
|
||
|
_pidmap.NameToPid( bmkCol );
|
||
|
}
|
||
|
|
||
|
for (unsigned i = 0; i < _cColumns; i++)
|
||
|
{
|
||
|
PROPID pidTmp = cols.Get(i);
|
||
|
const CFullPropSpec & ColId = *pidmap.Get(pidTmp);
|
||
|
|
||
|
if (ColId.IsPropertyPropid() &&
|
||
|
ColId.GetPropSet() == guidBmk)
|
||
|
{
|
||
|
Win4Assert( !fSequential );
|
||
|
if (ColId.GetPropertyPropid() == PROPID_DBBMK_BOOKMARK)
|
||
|
{
|
||
|
if (0 != pidmap.GetFriendlyName(pidTmp))
|
||
|
{
|
||
|
_pidmap.SetFriendlyName( 0, pidmap.GetFriendlyName(pidTmp) );
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
else if (ColId.GetPropertyPropid() == PROPID_DBBMK_CHAPTER)
|
||
|
{
|
||
|
_fChaptered = TRUE;
|
||
|
}
|
||
|
}
|
||
|
PROPID pidNew = _pidmap.NameToPid( ColId );
|
||
|
if (0 != pidmap.GetFriendlyName(pidTmp))
|
||
|
{
|
||
|
_pidmap.SetFriendlyName( pidNew, pidmap.GetFriendlyName(pidTmp) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// In case of duplicate columns, _cColumns needs to be adjusted.
|
||
|
Win4Assert( _pidmap.Count() > 1 );
|
||
|
_cColumns = _pidmap.Count() - 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::MapColumnID, private
|
||
|
//
|
||
|
// Synopsis: Map a column identifier to its column number in the
|
||
|
// cursor.
|
||
|
//
|
||
|
// Arguments: [pColumnId] - A pointer to the column identifier.
|
||
|
//
|
||
|
// Returns: The column number (1-based). Returns DB_INVALIDCOLUMN
|
||
|
// on error.
|
||
|
//
|
||
|
// History: 04 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CColumnsInfo::MapColumnID(
|
||
|
const DBID * pColumnId
|
||
|
) {
|
||
|
PROPID pid = pidInvalid;
|
||
|
|
||
|
if (pColumnId->eKind == DBKIND_PGUID_PROPID ||
|
||
|
pColumnId->eKind == DBKIND_PGUID_NAME)
|
||
|
{
|
||
|
DBID dbcolMapped = *pColumnId;
|
||
|
dbcolMapped.uGuid.guid = *pColumnId->uGuid.pguid;
|
||
|
|
||
|
if (pColumnId->eKind == DBKIND_PGUID_PROPID)
|
||
|
dbcolMapped.eKind = DBKIND_GUID_PROPID;
|
||
|
else
|
||
|
dbcolMapped.eKind = DBKIND_GUID_NAME;
|
||
|
|
||
|
pid = _pidmap.NameToPid(dbcolMapped);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pid = _pidmap.NameToPid(*pColumnId);
|
||
|
}
|
||
|
|
||
|
tbDebugOut(( DEB_ITRACE, "pid: 0x%x, _cColumns: %d\n",
|
||
|
pid, _cColumns ));
|
||
|
|
||
|
if (pid == pidInvalid || pid > _cColumns || (pid == 0 && _fSequential) )
|
||
|
return (ULONG) DB_INVALIDCOLUMN;
|
||
|
|
||
|
return pid;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::MapColumnIDs, public
|
||
|
//
|
||
|
// Synopsis: Map a column identifier to its column number in the
|
||
|
// rowset.
|
||
|
//
|
||
|
// Arguments: [cColumnIDs] -- # of elements in the arrays
|
||
|
// [rgColumnIDs] -- A pointer to the column identifiers
|
||
|
// [rgColumns] -- an array in which to return the column numbers.
|
||
|
//
|
||
|
// Returns: SCODE - DB_S_ERRORSOCCURRED, an element of rgColumnIDs was
|
||
|
// invalid
|
||
|
//
|
||
|
// Notes: Column numbers are 1-based.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP CColumnsInfo::MapColumnIDs(
|
||
|
DBORDINAL cColumnIDs,
|
||
|
const DBID rgColumnIDs[],
|
||
|
DBORDINAL rgColumns[])
|
||
|
{
|
||
|
_ErrorObject.ClearErrorInfo();
|
||
|
|
||
|
SCODE sc = S_OK;
|
||
|
|
||
|
if ((0 != cColumnIDs && 0 == rgColumnIDs) ||
|
||
|
0 == rgColumns)
|
||
|
return _ErrorObject.PostHResult(E_INVALIDARG, IID_IColumnsInfo);
|
||
|
|
||
|
if ( 0 == cColumnIDs )
|
||
|
return S_OK;
|
||
|
|
||
|
if ( _fNotPrepared )
|
||
|
return _ErrorObject.PostHResult(DB_E_NOTPREPARED, IID_IColumnsInfo);
|
||
|
|
||
|
if ( 0 == _cColumns )
|
||
|
return _ErrorObject.PostHResult(DB_E_NOCOMMAND, IID_IColumnsInfo);
|
||
|
|
||
|
unsigned cBadMapping = 0;
|
||
|
TRY
|
||
|
{
|
||
|
for (ULONG i = 0; i < cColumnIDs; i++)
|
||
|
{
|
||
|
ULONG ulColID = MapColumnID( &rgColumnIDs[i] );
|
||
|
rgColumns[i] = ulColID;
|
||
|
if (ulColID == DB_INVALIDCOLUMN)
|
||
|
cBadMapping++;
|
||
|
}
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
_ErrorObject.PostHResult(e.GetErrorCode(), IID_IColumnsInfo);
|
||
|
sc = GetOleError(e);
|
||
|
}
|
||
|
END_CATCH;
|
||
|
|
||
|
if (SUCCEEDED(sc) && cBadMapping)
|
||
|
sc = (cBadMapping == cColumnIDs) ? DB_E_ERRORSOCCURRED :
|
||
|
DB_S_ERRORSOCCURRED;
|
||
|
|
||
|
return sc;
|
||
|
} //MapColumnIDs
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::GetColumnInfo, public
|
||
|
//
|
||
|
// Synopsis: Return information about the columns in the rowset.
|
||
|
//
|
||
|
// Arguments: [pcColumns] - A pointer to where the number of columns
|
||
|
// will be returned.
|
||
|
// [prgInfo] - A pointer to where a pointer to an array of
|
||
|
// DBCOLUMNINFO structures describing the columns
|
||
|
// will be returned. This must be freed by the
|
||
|
// caller.
|
||
|
// [ppStringsBuffer] - A pointer to where extra data for strings
|
||
|
// will be returned. This must be freed by the
|
||
|
// caller if non-null.
|
||
|
//
|
||
|
// Returns: SCODE
|
||
|
//
|
||
|
// Notes: Some columns are standard columns available for all file
|
||
|
// stores. For these columns, full information about data
|
||
|
// type and sizes can be returned. For any other columns,
|
||
|
// we can only say that it has a variant type.
|
||
|
//
|
||
|
// History: 07 Nov 1994 AlanW Created
|
||
|
// 04 Feb 1995 AlanW Moved to CColumnsInfo and rewritten
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP CColumnsInfo::GetColumnInfo(
|
||
|
DBORDINAL * pcColumns,
|
||
|
DBCOLUMNINFO * * prgInfo,
|
||
|
WCHAR * * ppStringsBuffer)
|
||
|
{
|
||
|
_ErrorObject.ClearErrorInfo();
|
||
|
|
||
|
SCODE scResult = S_OK;
|
||
|
|
||
|
//
|
||
|
// Initialize arguments before returning errors
|
||
|
//
|
||
|
if ( pcColumns)
|
||
|
*pcColumns = 0;
|
||
|
if ( prgInfo )
|
||
|
*prgInfo = 0;
|
||
|
if (ppStringsBuffer )
|
||
|
*ppStringsBuffer = 0;
|
||
|
|
||
|
if (0 == pcColumns ||
|
||
|
0 == prgInfo ||
|
||
|
0 == ppStringsBuffer)
|
||
|
return _ErrorObject.PostHResult(E_INVALIDARG, IID_IColumnsInfo);
|
||
|
|
||
|
if ( _fNotPrepared )
|
||
|
return _ErrorObject.PostHResult(DB_E_NOTPREPARED, IID_IColumnsInfo);
|
||
|
|
||
|
if ( 0 == _cColumns )
|
||
|
return _ErrorObject.PostHResult(DB_E_NOCOMMAND, IID_IColumnsInfo);
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
unsigned iFirstCol = _fSequential ? 1 : 0;
|
||
|
unsigned cColumns = GetColumnCount() + 1 - iFirstCol;
|
||
|
|
||
|
//
|
||
|
// The total size required for the output array depends upon
|
||
|
// the size of variable data discovered in the column information.
|
||
|
// Although we could reallocate the memory we'll be writing into,
|
||
|
// we'll just run through the loop twice, once to compute the
|
||
|
// needed space, and the second time to copy the data out after
|
||
|
// doing our allocation.
|
||
|
//
|
||
|
ULONG cchNames = 0;
|
||
|
|
||
|
for (unsigned iCol = iFirstCol; iCol <= GetColumnCount(); iCol++)
|
||
|
{
|
||
|
const CFullPropSpec & ColId = *_pidmap.Get(iCol);
|
||
|
|
||
|
if (ColId.IsPropertyName())
|
||
|
{
|
||
|
cchNames += wcslen(ColId.GetPropertyName()) + 1;
|
||
|
}
|
||
|
|
||
|
WCHAR const * pwszColName = _pidmap.GetFriendlyName(iCol);
|
||
|
if (0 == pwszColName)
|
||
|
pwszColName = _FindColumnInfo(ColId).pwszName;
|
||
|
|
||
|
if (pwszColName)
|
||
|
{
|
||
|
cchNames += wcslen(pwszColName) + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
XArrayOLE<DBCOLUMNINFO> ColumnInfo( cColumns );
|
||
|
XArrayOLE<WCHAR> StringBuf( cchNames );
|
||
|
|
||
|
DBCOLUMNINFO *pColInfo = ColumnInfo.GetPointer();
|
||
|
WCHAR * pwcNames = StringBuf.GetPointer();
|
||
|
|
||
|
for (iCol = iFirstCol; iCol <= GetColumnCount(); iCol++, pColInfo++)
|
||
|
{
|
||
|
const CFullPropSpec & ColId = *_pidmap.Get(iCol);
|
||
|
const DBCOLUMNINFO & rColumnInfo = _FindColumnInfo( ColId );
|
||
|
|
||
|
//
|
||
|
// Copy the prototype column information, then update
|
||
|
// specific fields in the column info:
|
||
|
// column number
|
||
|
// column ID
|
||
|
// copies of strings
|
||
|
//
|
||
|
*pColInfo = rColumnInfo;
|
||
|
|
||
|
pColInfo->iOrdinal = iCol;
|
||
|
|
||
|
pColInfo->columnid.uGuid.guid = ColId.GetPropSet();
|
||
|
if (ColId.IsPropertyName())
|
||
|
{
|
||
|
pColInfo->columnid.eKind = DBKIND_GUID_NAME;
|
||
|
ULONG cch = wcslen(ColId.GetPropertyName()) + 1;
|
||
|
RtlCopyMemory(pwcNames, ColId.GetPropertyName(),
|
||
|
cch * sizeof (WCHAR));
|
||
|
pColInfo->columnid.uName.pwszName = pwcNames;
|
||
|
pwcNames += cch;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Win4Assert(ColId.IsPropertyPropid());
|
||
|
pColInfo->columnid.eKind = DBKIND_GUID_PROPID;
|
||
|
pColInfo->columnid.uName.ulPropid = ColId.GetPropertyPropid();
|
||
|
}
|
||
|
|
||
|
WCHAR const * pwszColName = _pidmap.GetFriendlyName(iCol);
|
||
|
if (0 == pwszColName)
|
||
|
pwszColName = _FindColumnInfo(ColId).pwszName;
|
||
|
|
||
|
if (pwszColName)
|
||
|
{
|
||
|
ULONG cch = wcslen(pwszColName) + 1;
|
||
|
RtlCopyMemory(pwcNames, pwszColName, cch * sizeof (WCHAR));
|
||
|
pColInfo->pwszName = pwcNames;
|
||
|
pwcNames += cch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Win4Assert( (unsigned)(pColInfo - ColumnInfo.GetPointer()) == cColumns );
|
||
|
|
||
|
*prgInfo = ColumnInfo.Acquire();
|
||
|
if (cchNames > 0)
|
||
|
*ppStringsBuffer = StringBuf.Acquire();
|
||
|
|
||
|
*pcColumns = cColumns;
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
scResult = e.GetErrorCode();
|
||
|
_ErrorObject.PostHResult(scResult, IID_IColumnsInfo);
|
||
|
if (scResult != E_OUTOFMEMORY)
|
||
|
scResult = E_FAIL;
|
||
|
}
|
||
|
END_CATCH;
|
||
|
|
||
|
return scResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::SetColumnBindings, public
|
||
|
//
|
||
|
// Synopsis: Set current column bindings on the cursor. Save in
|
||
|
// member variables. Workid is always added to the
|
||
|
// bindings for movable rowsets for use with bookmarks
|
||
|
// and hRows. Space for a USHORT reserved for row buffer
|
||
|
// refcounting is always allocated.
|
||
|
//
|
||
|
// Arguments: [rpQuery] - a reference to the PQuery for the query
|
||
|
// [hCursor] - a reference to the hCursor to have column
|
||
|
// bindings set on.
|
||
|
// [obRowRefcount] - on return, offset into the row buffer
|
||
|
// where a USHORT reference count can be stored.
|
||
|
// [obRowId] - on return, offset into the row buffer where
|
||
|
// the row identifier is stored. Not valid for
|
||
|
// sequential rowsets.
|
||
|
//
|
||
|
// Returns: Nothing. Throws on errors.
|
||
|
//
|
||
|
// Notes: Initializes the private members _cbRowWidth and _pColumns.
|
||
|
//
|
||
|
// History: 04 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CColumnsInfo::SetColumnBindings(
|
||
|
PQuery & rpQuery,
|
||
|
ULONG hCursor,
|
||
|
ULONG &obRowRefcount,
|
||
|
ULONG &obRowId,
|
||
|
ULONG &obChaptRefcount,
|
||
|
ULONG &obChaptId
|
||
|
) {
|
||
|
CTableRowAlloc RowMap( 0 );
|
||
|
USHORT maxAlignment = sizeof (USHORT);
|
||
|
|
||
|
obRowRefcount = RowMap.AllocOffset( sizeof (USHORT),
|
||
|
sizeof (USHORT),
|
||
|
TRUE );
|
||
|
|
||
|
if (_fChaptered)
|
||
|
obChaptRefcount = RowMap.AllocOffset( sizeof (USHORT),
|
||
|
sizeof (USHORT),
|
||
|
TRUE );
|
||
|
else
|
||
|
obChaptRefcount = 0xFFFFFFFF;
|
||
|
|
||
|
obRowId = 0xFFFFFFFF;
|
||
|
obChaptId = 0xFFFFFFFF;
|
||
|
BOOL fAddedWorkId = FALSE;
|
||
|
BOOL fMayDefer = FALSE;
|
||
|
|
||
|
// +1 In case WorkID or Path is added for rowid
|
||
|
|
||
|
XPtr<CTableColumnSet> XColumns( new CTableColumnSet( GetColumnCount() + 1 ));
|
||
|
|
||
|
unsigned cBoundColumns = 0;
|
||
|
|
||
|
tbDebugOut(( DEB_ITRACE, "original column count: %d\n", GetColumnCount() ));
|
||
|
for (unsigned iCol = 1; iCol <= GetColumnCount(); iCol++)
|
||
|
{
|
||
|
const CFullPropSpec & ColId = *_pidmap.Get( iCol );
|
||
|
const DBCOLUMNINFO & rColumnInfo = _FindColumnInfo( ColId );
|
||
|
|
||
|
tbDebugOut(( DEB_ITRACE, "colinfo::set, top of loop, cBoundColumns: %d\n",
|
||
|
cBoundColumns ));
|
||
|
tbDebugOut(( DEB_ITRACE, "adding '%ws'\n", rColumnInfo.pwszName ));
|
||
|
|
||
|
//
|
||
|
// If this is bookmark column, it will be mapped to the row ID
|
||
|
// column. It's only valid for locatable rowsets.
|
||
|
//
|
||
|
if ( (rColumnInfo.dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) &&
|
||
|
ColId.IsPropertyPropid() &&
|
||
|
ColId.GetPropertyPropid() == PROPID_DBBMK_BOOKMARK)
|
||
|
{
|
||
|
tbDebugOut(( DEB_ITRACE, "skipping bookmark column\n" ));
|
||
|
|
||
|
Win4Assert(! _fSequential );
|
||
|
if (_fSequential)
|
||
|
THROW(CException(E_FAIL));
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// the self columns is resolved in the accessor -- no binding needed
|
||
|
|
||
|
if ( ( ColId.IsPropertyPropid() ) &&
|
||
|
( ColId.GetPropertyPropid() == PROPID_DBSELF_SELF ) &&
|
||
|
( ColId.GetPropSet() == DBCOL_SELFCOLUMNS ) )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create the new column. Note that its PropID is the
|
||
|
// 1-based column ID.
|
||
|
//
|
||
|
XPtr<CTableColumn> TableCol(new CTableColumn( iCol ));
|
||
|
|
||
|
#ifndef ALWAYS_USE_VARIANT_BINDING
|
||
|
VARTYPE vt = rColumnInfo.wType;
|
||
|
|
||
|
switch (vt)
|
||
|
{
|
||
|
case DBTYPE_VARIANT:
|
||
|
{
|
||
|
#endif // ndef ALWAYS_USE_VARIANT_BINDING
|
||
|
|
||
|
fMayDefer = TRUE;
|
||
|
|
||
|
TableCol->SetValueField( DBTYPE_VARIANT,
|
||
|
RowMap.AllocOffset( sizeof (PROPVARIANT),
|
||
|
sizeof (LONGLONG),
|
||
|
TRUE ),
|
||
|
sizeof (PROPVARIANT));
|
||
|
|
||
|
// The status column is interesting for all columns
|
||
|
|
||
|
TableCol->SetStatusField( RowMap.AllocOffset( sizeof (BYTE),
|
||
|
sizeof (BYTE),
|
||
|
TRUE ),
|
||
|
sizeof (BYTE));
|
||
|
|
||
|
// Length is interesting, especially when the value is deferred
|
||
|
|
||
|
TableCol->SetLengthField( RowMap.AllocOffset( sizeof (ULONG),
|
||
|
sizeof (ULONG),
|
||
|
TRUE ),
|
||
|
sizeof (ULONG));
|
||
|
|
||
|
USHORT cbData, cbAlignment, rgfFlags;
|
||
|
CTableVariant::VartypeInfo(DBTYPE_VARIANT, cbData, cbAlignment, rgfFlags);
|
||
|
|
||
|
if ( cbAlignment > maxAlignment)
|
||
|
maxAlignment = cbAlignment;
|
||
|
|
||
|
#ifndef ALWAYS_USE_VARIANT_BINDING
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DBTYPE_DATE:
|
||
|
case DBTYPE_WSTR:
|
||
|
case DBTYPE_STR:
|
||
|
//
|
||
|
// Adjust DBTYPEs from the column info into ones that are
|
||
|
// better for binding.
|
||
|
//
|
||
|
if (vt == DBTYPE_DATE)
|
||
|
vt = VT_FILETIME;
|
||
|
else if (vt == DBTYPE_WSTR)
|
||
|
vt = VT_LPWSTR;
|
||
|
else if (vt == DBTYPE_STR)
|
||
|
vt = VT_LPSTR;
|
||
|
|
||
|
// NOTE: fall through
|
||
|
|
||
|
default:
|
||
|
|
||
|
USHORT cbData, cbAlignment, rgfFlags;
|
||
|
CTableVariant::VartypeInfo(vt, cbData, cbAlignment, rgfFlags);
|
||
|
|
||
|
if (rgfFlags & CTableVariant::MultiSize)
|
||
|
cbData = (USHORT) rColumnInfo.ulColumnSize;
|
||
|
|
||
|
Win4Assert(cbData != 0 || vt == VT_EMPTY);
|
||
|
|
||
|
if (cbData == 0 && vt != VT_EMPTY)
|
||
|
{
|
||
|
tbDebugOut(( DEB_WARN,
|
||
|
"CColumnInfo::SetColumnBindings - Unknown variant type %4x\n",
|
||
|
vt));
|
||
|
}
|
||
|
|
||
|
if (cbAlignment)
|
||
|
{
|
||
|
if (cbAlignment > maxAlignment)
|
||
|
{
|
||
|
maxAlignment = cbAlignment;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cbAlignment = 1;
|
||
|
}
|
||
|
|
||
|
if (cbData != 0)
|
||
|
{
|
||
|
TableCol->SetValueField( vt,
|
||
|
RowMap.AllocOffset( cbData,
|
||
|
cbAlignment,
|
||
|
TRUE ),
|
||
|
cbData);
|
||
|
|
||
|
Win4Assert( 0 == ( (TableCol->GetValueOffset()) % cbAlignment ) );
|
||
|
|
||
|
//
|
||
|
// The status column is interesting for almost all columns,
|
||
|
// even inline columns, since a summary catalog might have
|
||
|
// VT_EMPTY data for these columns (eg storage props).
|
||
|
//
|
||
|
TableCol->SetStatusField( RowMap.AllocOffset( sizeof (BYTE),
|
||
|
sizeof (BYTE),
|
||
|
TRUE ),
|
||
|
sizeof (BYTE));
|
||
|
}
|
||
|
}
|
||
|
#endif // ndef ALWAYS_USE_VARIANT_BINDING
|
||
|
|
||
|
//
|
||
|
// If this is the row ID column, save its offset in the row.
|
||
|
//
|
||
|
if (rColumnInfo.dwFlags & DBCOLUMNFLAGS_ISROWID)
|
||
|
{
|
||
|
#ifdef ALWAYS_USE_VARIANT_BINDING
|
||
|
Win4Assert(TableCol->GetStoredType() == VT_VARIANT &&
|
||
|
TableCol->IsValueStored() &&
|
||
|
TableCol->GetValueSize() == sizeof (PROPVARIANT));
|
||
|
PROPVARIANT prop;
|
||
|
obRowId = TableCol->GetValueOffset() +
|
||
|
(DWORD)((BYTE *) &prop.lVal - (BYTE *)&prop);
|
||
|
#else // ndef ALWAYS_USE_VARIANT_BINDING
|
||
|
Win4Assert(TableCol->GetStoredType() == VT_I4 &&
|
||
|
TableCol->IsValueStored() &&
|
||
|
TableCol->GetValueSize() == sizeof (ULONG));
|
||
|
obRowId = TableCol->GetValueOffset();
|
||
|
#endif // ndef ALWAYS_USE_VARIANT_BINDING
|
||
|
_iColRowId = iCol;
|
||
|
fAddedWorkId = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If this is the chapter column, save its offset in the row.
|
||
|
//
|
||
|
if (rColumnInfo.dwFlags & DBCOLUMNFLAGS_ISCHAPTER)
|
||
|
{
|
||
|
Win4Assert( _fChaptered );
|
||
|
#ifdef ALWAYS_USE_VARIANT_BINDING
|
||
|
Win4Assert(TableCol->GetStoredType() == VT_VARIANT &&
|
||
|
TableCol->IsValueStored() &&
|
||
|
TableCol->GetValueSize() == sizeof (PROPVARIANT));
|
||
|
PROPVARIANT prop;
|
||
|
obChaptId = TableCol->GetValueOffset() +
|
||
|
(DWORD)((BYTE *) &prop.lVal - (BYTE *)&prop);
|
||
|
#else // ndef ALWAYS_USE_VARIANT_BINDING
|
||
|
Win4Assert(TableCol->GetStoredType() == VT_I4 &&
|
||
|
TableCol->IsValueStored() &&
|
||
|
TableCol->GetValueSize() == sizeof (ULONG));
|
||
|
obChaptId = TableCol->GetValueOffset();
|
||
|
#endif // ndef ALWAYS_USE_VARIANT_BINDING
|
||
|
}
|
||
|
|
||
|
XColumns->Add(TableCol.GetPointer(), cBoundColumns++);
|
||
|
TableCol.Acquire();
|
||
|
}
|
||
|
|
||
|
tbDebugOut(( DEB_ITRACE, "colinfo::set, after loop, cBoundColumns: %d\n",
|
||
|
cBoundColumns ));
|
||
|
|
||
|
// Need to add workid for non-sequential queries so that bookmarks
|
||
|
// work, and either workid or path so that deferred values work.
|
||
|
|
||
|
if ( ( ( !_fSequential ) ||
|
||
|
( fMayDefer && rpQuery.CanDoWorkIdToPath() ) ) &&
|
||
|
( !fAddedWorkId ) )
|
||
|
{
|
||
|
tbDebugOut(( DEB_ITRACE, "colinfo::set, adding WID column\n" ));
|
||
|
|
||
|
//
|
||
|
// Need to add the row ID column to the bindings, so that bookmarks
|
||
|
// work, and deferred values can be loaded.
|
||
|
//
|
||
|
const DBCOLUMNINFO & rColumnInfo = _GetRowIdColumnInfo( );
|
||
|
|
||
|
unsigned iCol = _pidmap.NameToPid( rColumnInfo.columnid );
|
||
|
XPtr<CTableColumn> TableCol(new CTableColumn( iCol ));
|
||
|
_iColRowId = iCol;
|
||
|
|
||
|
Win4Assert (VT_I4 == rColumnInfo.wType);
|
||
|
|
||
|
if (sizeof (ULONG) > maxAlignment)
|
||
|
maxAlignment = sizeof (ULONG);
|
||
|
|
||
|
TableCol->SetValueField( VT_I4,
|
||
|
RowMap.AllocOffset( sizeof (ULONG),
|
||
|
sizeof (ULONG),
|
||
|
TRUE ),
|
||
|
sizeof (ULONG));
|
||
|
obRowId = TableCol->GetValueOffset();
|
||
|
|
||
|
TableCol->SetStatusField( RowMap.AllocOffset( sizeof (BYTE),
|
||
|
sizeof (BYTE),
|
||
|
TRUE ),
|
||
|
sizeof (BYTE));
|
||
|
|
||
|
XColumns->Add(TableCol.GetPointer(), cBoundColumns++);
|
||
|
TableCol.Acquire();
|
||
|
}
|
||
|
|
||
|
ULONG rem = RowMap.GetRowWidth() % maxAlignment;
|
||
|
|
||
|
if ( 0 == rem )
|
||
|
_cbRowWidth = RowMap.GetRowWidth();
|
||
|
else
|
||
|
_cbRowWidth = RowMap.GetRowWidth() + maxAlignment - rem;
|
||
|
|
||
|
rpQuery.SetBindings( hCursor,
|
||
|
_cbRowWidth,
|
||
|
XColumns.GetReference(),
|
||
|
_pidmap );
|
||
|
|
||
|
tbDebugOut(( DEB_ITRACE, "colinfo::set, old # cols %d, new # cols %d\n",
|
||
|
_cColumns, cBoundColumns ));
|
||
|
|
||
|
_cBoundColumns = cBoundColumns;
|
||
|
_pColumns = XColumns.Acquire();
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::Get1ColumnInfo, public
|
||
|
//
|
||
|
// Synopsis: Return information about a single column in the rowset.
|
||
|
//
|
||
|
// Arguments: [iColumn] - the column number whose column info is to be
|
||
|
// returned.
|
||
|
//
|
||
|
// Returns: DBCOLUMNINFO & - a pointer to column info for the column
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// History: 29 Mar 1995 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
const DBCOLUMNINFO & CColumnsInfo::Get1ColumnInfo(
|
||
|
ULONG iColumn
|
||
|
) /*const*/
|
||
|
{
|
||
|
const CFullPropSpec & ColId = *_pidmap.Get(iColumn);
|
||
|
|
||
|
return _FindColumnInfo( ColId );
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
|
||
|
STDMETHODIMP CRowset::GetColumnsRowset(
|
||
|
ULONG cSelections,
|
||
|
DBID rgColumnSelection[],
|
||
|
IRowset ** ppColCursor
|
||
|
) /*const*/ {
|
||
|
_ErrorObject.ClearErrorInfo();
|
||
|
return _ErrorObject.PostHResult(E_NOTIMPL, IID_IColumnsRowset);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CRowset::GetAvailableColumns(
|
||
|
ULONG * pcSelections,
|
||
|
DBID ** rgColumnSelection
|
||
|
) /*const*/ {
|
||
|
_ErrorObject.ClearErrorInfo();
|
||
|
return _ErrorObject.PostHResult(E_NOTIMPL, IID_IColumnsRowset);
|
||
|
}
|
||
|
#endif // INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Data declarations for _FindColumnInfo
|
||
|
//
|
||
|
// Notes: These arrays of structures are prototype column info.
|
||
|
// structures returned by _FindColumnInfo.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////
|
||
|
|
||
|
static const DBCOLUMNINFO aStoragePropDescs[] = {
|
||
|
{ L"FileDirectoryName", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE, MAX_PATH, // storage props are never deferred
|
||
|
DBTYPE_WSTR, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_DIRECTORY ) }
|
||
|
},
|
||
|
|
||
|
{ L"ClassID", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (GUID),
|
||
|
DBTYPE_GUID, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_CLASSID ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileStorageType", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (ULONG),
|
||
|
DBTYPE_UI4, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_STORAGETYPE ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileIndex", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
|
||
|
DBTYPE_I8, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_FILEINDEX ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileUSN", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
|
||
|
DBTYPE_I8, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_LASTCHANGEUSN ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileName", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE, MAX_PATH, // storage props are never deferred
|
||
|
DBTYPE_WSTR, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_NAME ) }
|
||
|
},
|
||
|
|
||
|
{ L"FilePathName", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE, MAX_PATH, // storage props are never deferred
|
||
|
DBTYPE_WSTR, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_PATH ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileSize", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
|
||
|
DBTYPE_I8, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_SIZE ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileAttributes", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (ULONG),
|
||
|
DBTYPE_UI4, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_ATTRIBUTES ) }
|
||
|
},
|
||
|
|
||
|
// NOTE: file times are typed as DBTYPE_DATE, but are bound to the
|
||
|
// table as VT_FILETIME.
|
||
|
{ L"FileWriteTime", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
|
||
|
DBTYPE_DATE, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_WRITETIME ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileCreateTime", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
|
||
|
DBTYPE_DATE, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_CREATETIME ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileAccessTime", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
|
||
|
DBTYPE_DATE, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_ACCESSTIME ) }
|
||
|
},
|
||
|
|
||
|
{ L"FileShortName", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE, 13, // storage props are never deferred
|
||
|
DBTYPE_WSTR, 0xff, 0xff,
|
||
|
{ PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_SHORTNAME ) }
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const ULONG cStoragePropDescs =
|
||
|
sizeof aStoragePropDescs /
|
||
|
sizeof aStoragePropDescs[0];
|
||
|
|
||
|
|
||
|
//
|
||
|
// Standard query properties.
|
||
|
// Does not include pidAll or pidContent, those are used only in restrictions.
|
||
|
//
|
||
|
|
||
|
static const DBCOLUMNINFO aQueryPropDescs[] = {
|
||
|
{ L"QueryRankvector", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof(PROPVARIANT),
|
||
|
DBTYPE_VARIANT, 0xff, 0xff,
|
||
|
{ DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_RANKVECTOR ) }
|
||
|
},
|
||
|
|
||
|
{ L"QueryRank", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_RANK ) }
|
||
|
},
|
||
|
|
||
|
{ L"QueryHitCount", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_HITCOUNT ) }
|
||
|
},
|
||
|
|
||
|
{ L"WorkID", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH|DBCOLUMNFLAGS_ISROWID, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_WORKID ) }
|
||
|
},
|
||
|
|
||
|
{ L"QueryUnfiltered", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof(BOOL),
|
||
|
DBTYPE_BOOL, 0xff, 0xff,
|
||
|
{ DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_UNFILTERED ) }
|
||
|
},
|
||
|
|
||
|
{ L"QueryVirtualPath", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE, MAX_PATH,
|
||
|
DBTYPE_WSTR, 0xff, 0xff,
|
||
|
{ DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_VIRTUALPATH ) }
|
||
|
},
|
||
|
|
||
|
#if defined( DISPID_QUERY_NLIRRANK )
|
||
|
{ L"NLIRRank", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_NLIRRANK ) }
|
||
|
},
|
||
|
#endif // defined( DISPID_QUERY_NLIRRANK )
|
||
|
};
|
||
|
|
||
|
const ULONG cQueryPropDescs =
|
||
|
sizeof aQueryPropDescs /
|
||
|
sizeof aQueryPropDescs[0];
|
||
|
|
||
|
|
||
|
static DBCOLUMNINFO const aBmkPropDescs[] = {
|
||
|
{ L"Bookmark", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISBOOKMARK|DBCOLUMNFLAGS_ISFIXEDLENGTH,
|
||
|
sizeof (CI_TBL_BMK),
|
||
|
DBTYPE_BYTES, 0xff, 0xff,
|
||
|
{ DBBMKGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PROPID_DBBMK_BOOKMARK ) }
|
||
|
},
|
||
|
{ L"Chapter", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISCHAPTER|DBCOLUMNFLAGS_ISBOOKMARK|DBCOLUMNFLAGS_ISFIXEDLENGTH,
|
||
|
sizeof (CI_TBL_CHAPT),
|
||
|
DBTYPE_BYTES, 0xff, 0xff,
|
||
|
{ DBBMKGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PROPID_DBBMK_CHAPTER ) }
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const ULONG cBmkPropDescs =
|
||
|
sizeof aBmkPropDescs /
|
||
|
sizeof aBmkPropDescs[0];
|
||
|
|
||
|
|
||
|
// CLEANCODE: ole-db spec bug #1271 - const GUID init. less than useful
|
||
|
|
||
|
#ifndef DBSELFGUID
|
||
|
#define DBSELFGUID {0xc8b52231,0x5cf3,0x11ce,{0xad,0xe5,0x00,0xaa,0x00,0x44,0x77,0x3d}}
|
||
|
#endif // ndef DBSELFGUID
|
||
|
|
||
|
static DBCOLUMNINFO const aSelfPropDescs[] = {
|
||
|
{ L"Self", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH,
|
||
|
sizeof( int ),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBSELFGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PROPID_DBSELF_SELF ) }
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const ULONG cSelfPropDescs =
|
||
|
sizeof aSelfPropDescs /
|
||
|
sizeof aSelfPropDescs[0];
|
||
|
|
||
|
#ifdef INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
|
||
|
|
||
|
static const DBCOLUMNINFO aColInfoPropDescs[] = {
|
||
|
|
||
|
{ L"ColumnId", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, 3 * sizeof(PROPVARIANT),
|
||
|
DBTYPE_VARIANT|DBTYPE_VECTOR, 0xff, 0xff,
|
||
|
{ DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)1 }
|
||
|
},
|
||
|
|
||
|
{ L"ColumnName", 0, 0,
|
||
|
0, 20,
|
||
|
DBTYPE_WSTR, 0xff, 0xff,
|
||
|
{ DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)2 }
|
||
|
},
|
||
|
|
||
|
{ L"ColumnNumber", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)3 }
|
||
|
},
|
||
|
|
||
|
{ L"ColumnType", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof(USHORT),
|
||
|
DBTYPE_I2, 0xff, 0xff,
|
||
|
{ DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)4 }
|
||
|
},
|
||
|
|
||
|
{ L"ColumnLength", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)5 }
|
||
|
},
|
||
|
|
||
|
{ L"ColumnPrecision", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)6 }
|
||
|
},
|
||
|
|
||
|
{ L"ColumnScale", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)7 }
|
||
|
},
|
||
|
|
||
|
{ L"ColumnFlags", 0, 0,
|
||
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
|
||
|
DBTYPE_I4, 0xff, 0xff,
|
||
|
{ DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)8 }
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const ULONG cColInfoPropDescs =
|
||
|
sizeof aColInfoPropDescs /
|
||
|
sizeof aColInfoPropDescs[0];
|
||
|
#endif // INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
|
||
|
|
||
|
//
|
||
|
// Array of column descriptions per known propset
|
||
|
// Each referenced array must have the same Guid for each element in
|
||
|
// the array.
|
||
|
//
|
||
|
|
||
|
const CColumnsInfo::SPropSetInfo CColumnsInfo::aPropSets [ ] = {
|
||
|
#define IPROPSET_STORAGE 0 // Storage property set index
|
||
|
{ cStoragePropDescs, aStoragePropDescs },
|
||
|
{ cQueryPropDescs, aQueryPropDescs },
|
||
|
{ cBmkPropDescs, aBmkPropDescs },
|
||
|
{ cSelfPropDescs, aSelfPropDescs },
|
||
|
|
||
|
#ifdef INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
|
||
|
{ cColInfoPropDescs, aColInfoPropDescs },
|
||
|
#endif // INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
|
||
|
};
|
||
|
|
||
|
const ULONG CColumnsInfo::cPropSets =
|
||
|
sizeof CColumnsInfo::aPropSets /
|
||
|
sizeof CColumnsInfo::aPropSets[0];
|
||
|
|
||
|
DBCOLUMNINFO const DefaultColumnInfo = {
|
||
|
0, 0, 0,
|
||
|
DBCOLUMNFLAGS_ISNULLABLE | DBCOLUMNFLAGS_MAYDEFER | DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (PROPVARIANT),
|
||
|
DBTYPE_VARIANT, 0xff, 0xff,
|
||
|
{ {0,0,0,{0,0,0,0,0,0,0,0}}, DBKIND_GUID_PROPID, (LPWSTR)0 }
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::_FindColumnInfo, static
|
||
|
//
|
||
|
// Synopsis: Return information about a particular column ID.
|
||
|
//
|
||
|
// Arguments: [ColId] - Column ID to be looked up.
|
||
|
//
|
||
|
// Returns: DBCOLUMNINFO - the column information for the row looked up.
|
||
|
//
|
||
|
// Notes: Some columns are standard columns available for all file
|
||
|
// stores. For these columns, full information about data
|
||
|
// type and sizes can be returned. For any other columns,
|
||
|
// a generic column information structure is returned.
|
||
|
//
|
||
|
// History: 10 Feb 1995 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
DBCOLUMNINFO const & CColumnsInfo::_FindColumnInfo(
|
||
|
const CFullPropSpec & ColId
|
||
|
) {
|
||
|
DBCOLUMNINFO const * pColInfo = &DefaultColumnInfo;
|
||
|
|
||
|
//
|
||
|
// All custom information we return has propids, not prop names.
|
||
|
// Valid property IDs start at 2
|
||
|
//
|
||
|
|
||
|
if (ColId.IsPropertyPropid())
|
||
|
{
|
||
|
for (unsigned iPropSet = 0; iPropSet < cPropSets; iPropSet++)
|
||
|
{
|
||
|
if (ColId.GetPropSet() ==
|
||
|
aPropSets[iPropSet].aPropDescs[0].columnid.uGuid.guid)
|
||
|
{
|
||
|
//
|
||
|
// Found the guid for the propset, now try to find the
|
||
|
// propid.
|
||
|
//
|
||
|
ULONG ulPropId = ColId.GetPropertyPropid();
|
||
|
|
||
|
Win4Assert( ulPropId != PID_CODEPAGE &&
|
||
|
ulPropId != PID_DICTIONARY);
|
||
|
|
||
|
for (unsigned iDesc = 0;
|
||
|
iDesc < aPropSets[iPropSet].cProps;
|
||
|
iDesc++)
|
||
|
{
|
||
|
if (ulPropId ==
|
||
|
aPropSets[iPropSet].aPropDescs[iDesc].columnid.uName.ulPropid)
|
||
|
{
|
||
|
pColInfo = &aPropSets[iPropSet].aPropDescs[iDesc];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return *pColInfo;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CColumnsInfo::_GetRowIdColumnInfo, static
|
||
|
//
|
||
|
// Synopsis: Return information about the row ID column
|
||
|
//
|
||
|
// Arguments: - None -
|
||
|
//
|
||
|
// Returns: DBCOLUMNINFO - the column information for the row looked up.
|
||
|
//
|
||
|
// Notes: It is assumed that there is only one row ID column in the
|
||
|
// standard column info. This may need to change for chaptered
|
||
|
// rowsets.
|
||
|
//
|
||
|
// History: 15 Mar 1995 AlanW Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
DBCOLUMNINFO const & CColumnsInfo::_GetRowIdColumnInfo(
|
||
|
) {
|
||
|
DBCOLUMNINFO const * pColInfo = 0;
|
||
|
|
||
|
for (unsigned iPropSet = 0;
|
||
|
iPropSet < cPropSets && pColInfo == 0;
|
||
|
iPropSet++)
|
||
|
{
|
||
|
for (unsigned iDesc = 0;
|
||
|
iDesc < aPropSets[iPropSet].cProps;
|
||
|
iDesc++)
|
||
|
{
|
||
|
if ( aPropSets[iPropSet].aPropDescs[iDesc].dwFlags &
|
||
|
DBCOLUMNFLAGS_ISROWID)
|
||
|
{
|
||
|
pColInfo = &aPropSets[iPropSet].aPropDescs[iDesc];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Win4Assert(pColInfo != 0);
|
||
|
return *pColInfo;
|
||
|
}
|