|
|
//---------------------------------------------------------------------------
// RowsetColumn.cpp : RowsetColumn implementation
//
// Copyright (c) 1996 Microsoft Corporation, All Rights Reserved
// Developed by Sheridan Software Systems, Inc.
//---------------------------------------------------------------------------
#include "stdafx.h"
#include "RSColumn.h"
SZTHISFILE
//=--------------------------------------------------------------------------=
// CVDRowsetColumn - Constructor
//
CVDRowsetColumn::CVDRowsetColumn() { m_ulOrdinal = 0;
m_wType = 0; m_pwszBaseColumnName = NULL; m_pwszBaseName = NULL; m_dwBindType = 0; m_lcidCollatingOrder = 0; m_pwszDefaultValue = NULL; m_cbEntryIDMaxLength = 0; m_cbMaxLength = 0; m_pwszName = NULL; m_dwNumber = 0; m_dwScale = 0; m_dwCursorType = 0; m_dwUpdatable = 0; m_dwVersion = 0; m_dwStatus = 0;
m_bool.fInitialized = FALSE; m_bool.fAutoIncrement = FALSE; m_bool.fCaseSensitive = TRUE; m_bool.fDataColumn = FALSE; m_bool.fFixed = FALSE; m_bool.fHasDefault = FALSE; m_bool.fMultiValued = FALSE; m_bool.fNullable = FALSE; m_bool.fSearchable = FALSE; m_bool.fUnique = FALSE;
m_ulMaxStrLen = 0;
memset(&m_columnID, 0, sizeof(DBID)); memset(&m_cursorColumnID, 0, sizeof(CURSOR_DBCOLUMNID));
#ifdef _DEBUG
g_cVDRowsetColumnCreated++; #endif
}
//=--------------------------------------------------------------------------=
// ~CVDRowsetColumn - Destructor
//
CVDRowsetColumn::~CVDRowsetColumn() { delete [] m_pwszBaseColumnName; delete [] m_pwszBaseName; delete [] m_pwszDefaultValue; delete [] m_pwszName;
if (m_columnID.eKind == DBKIND_PGUID_NAME || m_columnID.eKind == DBKIND_PGUID_PROPID) delete m_columnID.uGuid.pguid;
if (m_columnID.eKind == DBKIND_GUID_NAME || m_columnID.eKind == DBKIND_NAME || m_columnID.eKind == DBKIND_PGUID_NAME) delete [] m_columnID.uName.pwszName;
if (m_cursorColumnID.dwKind == CURSOR_DBCOLKIND_GUID_NAME || m_cursorColumnID.dwKind == CURSOR_DBCOLKIND_NAME) delete [] m_cursorColumnID.lpdbsz;
#ifdef _DEBUG
g_cVDRowsetColumnDestroyed++; #endif
}
//=--------------------------------------------------------------------------=
// Initialize - Initialize rowset column object from IRowset metadata (#1)
//=--------------------------------------------------------------------------=
// This function converts and stores IRowset metadata in ICursor format
//
// Parameters:
// ulOrdinal - [in] original IRowset ordinal of column
// ulCursorOrdinal - [in] newly assigned ICursor ordinal of column
// pColumnInfo - [in] a pointer to an IRowset DBCOLUMNINFO structure
// where to retrieve metadata
// cbMaxBookmark - [in] maximum size of an IRowset bookmark
// pBookmarkColumnID - [in] a pointer to bookmark column identifier if this
// is a bookmark column, otherwise NULL
//
// Output:
// BOOL - TRUE if successful
//
// Notes:
// This function should only be called once
//
BOOL CVDRowsetColumn::Initialize(ULONG ulOrdinal, ULONG ulCursorOrdinal, DBCOLUMNINFO * pColumnInfo, ULONG cbMaxBookmark, CURSOR_DBCOLUMNID * pBookmarkColumnID) { if (m_bool.fInitialized) { ASSERT(FALSE, VD_ASSERTMSG_COLALREADYINITIALIZED) return FALSE; }
m_ulOrdinal = ulOrdinal;
// Store IRowset metadata
m_wType = pColumnInfo->wType; m_columnID = pColumnInfo->columnid;
// make copy of guid if necessary
if (m_columnID.eKind == DBKIND_PGUID_NAME || m_columnID.eKind == DBKIND_PGUID_PROPID) { m_columnID.uGuid.pguid = new GUID;
if (!m_columnID.uGuid.pguid) return E_OUTOFMEMORY;
memcpy(m_columnID.uGuid.pguid, pColumnInfo->columnid.uGuid.pguid, sizeof(GUID)); }
// make copy of name if necessary
if (m_columnID.eKind == DBKIND_GUID_NAME || m_columnID.eKind == DBKIND_NAME || m_columnID.eKind == DBKIND_PGUID_NAME) { const int nLength = lstrlenW(pColumnInfo->columnid.uName.pwszName);
m_columnID.uName.pwszName = new WCHAR[nLength + 1];
if (!m_columnID.uName.pwszName) return E_OUTOFMEMORY;
memcpy(m_columnID.uName.pwszName, pColumnInfo->columnid.uName.pwszName, (nLength + 1) * sizeof(WCHAR)); }
// Store ICursor metadata
if (pColumnInfo->dwFlags & DBCOLUMNFLAGS_MAYDEFER) m_dwBindType = CURSOR_DBBINDTYPE_BOTH; else m_dwBindType = CURSOR_DBBINDTYPE_DATA;
if (!pBookmarkColumnID) m_cursorColumnID = ColumnIDToCursorColumnID(pColumnInfo->columnid, ulCursorOrdinal); else m_cursorColumnID = *pBookmarkColumnID; // use supplied bookmark column identifier
if (m_dwBindType == CURSOR_DBBINDTYPE_BOTH) m_cbEntryIDMaxLength = sizeof(ULONG) + sizeof(ULONG) + cbMaxBookmark; else m_cbEntryIDMaxLength = 0;
// rowset types DBTYPE_GUID and DBTYPE_DBTIMESTAMP are returned as CURSOR_DBTYPE_LPWSTRs
if (pColumnInfo->wType == DBTYPE_GUID || pColumnInfo->wType == DBTYPE_DBTIMESTAMP) m_cbMaxLength = 64; else m_cbMaxLength = pColumnInfo->ulColumnSize;
if (pColumnInfo->pwszName) { const int nLength = lstrlenW(pColumnInfo->pwszName);
m_pwszName = new WCHAR[nLength + 1];
if (!m_pwszName) return E_OUTOFMEMORY;
memcpy(m_pwszName, pColumnInfo->pwszName, (nLength + 1) * sizeof(WCHAR)); }
m_dwNumber = ulCursorOrdinal;
m_dwScale = pColumnInfo->bScale;
m_dwCursorType = TypeToCursorType(pColumnInfo->wType);
if (pColumnInfo->dwFlags & DBCOLUMNFLAGS_WRITE) m_dwUpdatable = CURSOR_DBUPDATEABLE_UPDATEABLE;
if (!(pColumnInfo->dwFlags & DBCOLUMNFLAGS_ISBOOKMARK)) m_bool.fDataColumn = TRUE;
if (pColumnInfo->dwFlags & DBCOLUMNFLAGS_ISFIXEDLENGTH) { m_bool.fFixed = TRUE; m_ulMaxStrLen = GetCursorTypeMaxStrLen(m_dwCursorType, m_cbMaxLength); }
if (pColumnInfo->dwFlags & DBCOLUMNFLAGS_MAYBENULL) m_bool.fNullable = TRUE;
m_bool.fInitialized = TRUE;
return TRUE; }
//=--------------------------------------------------------------------------=
// Initialize - Initialize rowset column object from meta-metadata (#2)
//=--------------------------------------------------------------------------=
// The function stores ICursor meta-metadata
//
// Parameters:
// cursorColumnID - [in] ICursor column identifier
// fDataColumn - [in] is data column?
// cbMaxLength - [in] maximum length of this datatype
// pszName - [in] column name
// dwCursorType - [in] datatype
// dwNumber - [in] ordinal position
//
// Output:
// BOOL - TRUE if successful
//
// Notes:
// This function should only be called once
//
BOOL CVDRowsetColumn::Initialize(const CURSOR_DBCOLUMNID * pCursorColumnID, BOOL fDataColumn, ULONG cbMaxLength, CHAR * pszName, DWORD dwCursorType, DWORD dwNumber) { if (m_bool.fInitialized) { ASSERT(FALSE, VD_ASSERTMSG_COLALREADYINITIALIZED) return FALSE; }
// Store ICursor meta-metadata
m_dwBindType = CURSOR_DBBINDTYPE_DATA;
m_cursorColumnID = *pCursorColumnID;
m_cbEntryIDMaxLength = 0;
m_cbMaxLength = cbMaxLength;
if (pszName) { MAKE_WIDEPTR_FROMANSI(pwszName, pszName);
const int nLength = lstrlenW(pwszName);
m_pwszName = new WCHAR[nLength + 1];
if (!m_pwszName) return E_OUTOFMEMORY;
memcpy(m_pwszName, pwszName, (nLength + 1) * sizeof(WCHAR)); }
m_dwNumber = dwNumber;
m_dwScale = 0;
m_dwCursorType = dwCursorType;
m_dwUpdatable = CURSOR_DBUPDATEABLE_NOTUPDATEABLE;
m_bool.fDataColumn = fDataColumn; m_bool.fFixed = TRUE; m_bool.fNullable = FALSE;
m_bool.fInitialized = TRUE;
return TRUE; }
//=--------------------------------------------------------------------------=
// SetStringProperty
//=--------------------------------------------------------------------------=
// The function is called from SetBaseColumnName, SetBaseName and SetDefaultValue
//
// Parameters:
// ppStringProp - [in] A ptr to the ptr that holds the string value
// pNewString - [in] A pointer to the new string value
// ulLength - [in] the length of the string in bytes
//
// Notes:
//
void CVDRowsetColumn::SetStringProperty(WCHAR ** ppStringProp, WCHAR * pNewString, ULONG ulLength) { // free old string prop if any
delete [] *ppStringProp;
// if ulLength = zero then just return
if (!ulLength) { *ppStringProp = NULL; return; }
ASSERT_POINTER_LEN(pNewString, ulLength); *ppStringProp = new WCHAR[ulLength + sizeof(WCHAR)];
if (*ppStringProp) { // init null terminator
(*ppStringProp)[ulLength] = 0; // copy string over
memcpy(*ppStringProp, pNewString, ulLength); } }
//=--------------------------------------------------------------------------=
// ColumnIDToCursorColumnID - Convert rowset column ID to cursor column ID
//=--------------------------------------------------------------------------=
// Converts an IRowset DBID structure into its ICursor DBCOLUMNID equivalent
//
// Parameters:
// columnID - [in] the IRowset column identifier
// ulCursorOrdinal - [in] the column's ordinal position in ICursor
//
// Output:
// CURSOR_DBCOLUMNID - The ICursor CURSOR_DBCOLUMNID equivalent of columnID
//
// Notes:
//
CURSOR_DBCOLUMNID CVDRowsetColumn::ColumnIDToCursorColumnID(const DBID& columnID, ULONG ulCursorOrdinal) { CURSOR_DBCOLUMNID cursorColumnID;
GUID guidNumberOnly = CURSOR_GUID_NUMBERONLY;
cursorColumnID.guid = guidNumberOnly; cursorColumnID.dwKind = CURSOR_DBCOLKIND_GUID_NUMBER; cursorColumnID.lNumber = ulCursorOrdinal;
return cursorColumnID;
// The following code is the old implementation of this function. It caused problems with some
// cursor consumers because it tried to create a cursor column identifier as close as possible
// to the rowset column identifier, thus utilized the problematic lpdbsz member.
/*
CURSOR_DBCOLUMNID ID;
switch (columnID.eKind) { case DBKIND_GUID_NAME: ID.guid = columnID.uGuid.guid; ID.dwKind = CURSOR_DBCOLKIND_GUID_NAME; ID.lpdbsz = columnID.uName.pwszName; break;
case DBKIND_GUID_PROPID: ID.guid = columnID.uGuid.guid; ID.dwKind = CURSOR_DBCOLKIND_GUID_NUMBER; ID.lNumber = ulCursorOrdinal; break; case DBKIND_NAME: ID.dwKind = CURSOR_DBCOLKIND_NAME; ID.lpdbsz = columnID.uName.pwszName; break;
case DBKIND_PGUID_NAME: ID.guid = *columnID.uGuid.pguid; ID.dwKind = CURSOR_DBCOLKIND_GUID_NAME; ID.lpdbsz = columnID.uName.pwszName; break;
case DBKIND_PGUID_PROPID: ID.guid = *columnID.uGuid.pguid; ID.dwKind = CURSOR_DBCOLKIND_GUID_NUMBER; ID.lNumber = ulCursorOrdinal; break;
case DBKIND_GUID: ID.guid = columnID.uGuid.guid; ID.dwKind = CURSOR_DBCOLKIND_GUID_NUMBER; ID.lNumber = ulCursorOrdinal; break;
case DBKIND_PROPID: memset(&ID.guid, 0, sizeof(GUID)); // encode ordinal in guid
ID.guid.Data1 = ulCursorOrdinal; ID.dwKind = CURSOR_DBCOLKIND_GUID_NUMBER; ID.lNumber = ulCursorOrdinal; break; }
// make copy of name if necessary
if (ID.dwKind == CURSOR_DBCOLKIND_GUID_NAME || ID.dwKind == CURSOR_DBCOLKIND_NAME) { const int nLength = lstrlenW(columnID.uName.pwszName);
ID.lpdbsz = new WCHAR[nLength + 1];
if (ID.lpdbsz) memcpy(ID.lpdbsz, columnID.uName.pwszName, (nLength + 1) * sizeof(WCHAR)); }
return ID; */ }
//=--------------------------------------------------------------------------=
// TypeToCursorType - Convert rowset datatype to cursor datatype
//=--------------------------------------------------------------------------=
// Converts a IRowset DBTYPE value into its ICursor DBVARENUM equivalent
//
// Parameters:
// wType - [in] the IRowset datatype
//
// Output:
// CURSOR_DBVARENUM - The ICursor DBVARENUM equivalent of DBTYPE
//
// Notes:
//
CURSOR_DBVARENUM CVDRowsetColumn::TypeToCursorType(DBTYPE wType) { DWORD dwType = 0;
switch (wType) { case DBTYPE_ERROR: dwType = CURSOR_DBTYPE_HRESULT; break;
case DBTYPE_VARIANT: dwType = CURSOR_DBTYPE_ANYVARIANT; break;
case DBTYPE_UI2: dwType = CURSOR_DBTYPE_UI2; break;
case DBTYPE_UI4: dwType = CURSOR_DBTYPE_UI4; break;
case DBTYPE_UI8: dwType = CURSOR_DBTYPE_UI8; break;
case DBTYPE_BYTES: dwType = CURSOR_DBTYPE_BLOB; break;
case DBTYPE_STR: dwType = VT_BSTR; break;
case DBTYPE_WSTR: dwType = CURSOR_DBTYPE_LPWSTR; break;
case DBTYPE_NUMERIC: dwType = CURSOR_DBTYPE_R8; break;
//case DBTYPE_HCHAPTER: <- doesn't exist in new spec
// break; // no equivalent
case DBTYPE_UDT: break; // no equivalent
case DBTYPE_DBDATE: dwType = CURSOR_DBTYPE_DATE; break;
case DBTYPE_DBTIME: dwType = CURSOR_DBTYPE_DATE; break;
// rowset types DBTYPE_GUID and DBTYPE_DBTIMESTAMP are returned as CURSOR_DBTYPE_LPWSTRs
case DBTYPE_GUID: case DBTYPE_DBTIMESTAMP: dwType = CURSOR_DBTYPE_LPWSTR; break;
default: dwType = wType; }
return (CURSOR_DBVARENUM)dwType; }
//=--------------------------------------------------------------------------=
// CursorTypeToType - Convert cursor datatype to rowset datatype
//=--------------------------------------------------------------------------=
// Converts a ICursor DBVARENUM value into its IRowset DBTYPE equivalent
//
// Parameters:
// CURSOR_DBVARENUM - [in] the ICursor value
//
// Output:
// DBTYPE - The IRowset DBTYPE equivalent of DBVARENUM
//
// Notes:
//
DBTYPE CVDRowsetColumn::CursorTypeToType(CURSOR_DBVARENUM dwCursorType) { DBTYPE wType = 0; switch (dwCursorType) { case CURSOR_DBTYPE_HRESULT: wType = DBTYPE_ERROR; break; case CURSOR_DBTYPE_LPSTR: wType = DBTYPE_STR; break; case CURSOR_DBTYPE_LPWSTR: wType = DBTYPE_WSTR; break; case CURSOR_DBTYPE_FILETIME: wType = DBTYPE_DBTIMESTAMP; break; case CURSOR_DBTYPE_BLOB: wType = DBTYPE_BYTES; break; case CURSOR_DBTYPE_DBEXPR: break; // no equivalent
case CURSOR_DBTYPE_UI2: wType = DBTYPE_UI2; break; case CURSOR_DBTYPE_UI4: wType = DBTYPE_UI4; break; case CURSOR_DBTYPE_UI8: wType = DBTYPE_UI8; break; case CURSOR_DBTYPE_COLUMNID: wType = DBTYPE_GUID; break; case CURSOR_DBTYPE_BYTES: wType = DBTYPE_BYTES; break; case CURSOR_DBTYPE_CHARS: wType = DBTYPE_STR; break; case CURSOR_DBTYPE_WCHARS: wType = DBTYPE_WSTR; break; case CURSOR_DBTYPE_ANYVARIANT: wType = DBTYPE_VARIANT; break;
default: wType = (WORD)dwCursorType; }
return wType; }
//=--------------------------------------------------------------------------=
// GetCursorTypeMaxStrLen - Get the buffer size in characters required by
// cursor data type when represented as a string
// (doesn't include NULL terminator)
//
// Notes:
//
// The way these values where computed is as follows:
//
// (1) the maximum precision for each datatype was taken from "Precision of Numeric Data Types" in
// appendix A of the "OLE DB Programmer's Reference, Volume 2".
// (2) the precision was then divided by two and added to the original precision to allow space for
// numberic symbols, like negative signs, dollar signs, commas, etc., that might be present.
// (3) the sum was then doubled to allow for multibyte character sets.
//
// Since this table is not appropriate for floating point datatypes, their values where computed based
// on the string length of the minimum/maximum possible values for these datatypes, then doubled.
//
// datatype minimum value maximum value length
// -------- ------------- ------------- ------
// float 1.175494351e-38 3.402823466e+38 15
// double 2.2250738585072014e-308 1.7976931348623158e+308 23
//
ULONG CVDRowsetColumn::GetCursorTypeMaxStrLen(DWORD dwCursorType, ULONG cbMaxLength) { ULONG ulMaxStrLen = cbMaxLength; // default for fixed length strings
switch (dwCursorType) { case VT_I1: ulMaxStrLen = (3 + 1) * 2; break;
case CURSOR_DBTYPE_I2: ulMaxStrLen = (5 + 2) * 2; break;
case CURSOR_DBTYPE_I4: ulMaxStrLen = (10 + 5) * 2; break;
case CURSOR_DBTYPE_I8: ulMaxStrLen = (19 + 9) * 2; break;
case CURSOR_DBTYPE_R4: ulMaxStrLen = (15) * 2; break;
case CURSOR_DBTYPE_R8: ulMaxStrLen = (23) * 2; break;
case CURSOR_DBTYPE_CY: ulMaxStrLen = (19 + 9) * 2; break;
case CURSOR_DBTYPE_DATE: ulMaxStrLen = (32 + 16) * 2; break;
case CURSOR_DBTYPE_FILETIME: ulMaxStrLen = (32 + 16) * 2; break;
case CURSOR_DBTYPE_BOOL: ulMaxStrLen = (5 + 2) * 2; break;
case VT_UI1: ulMaxStrLen = (3 + 1) * 2; break;
case CURSOR_DBTYPE_UI2: ulMaxStrLen = (5 + 2) * 2; break;
case CURSOR_DBTYPE_UI4: ulMaxStrLen = (10 + 5) * 2; break;
case CURSOR_DBTYPE_UI8: ulMaxStrLen = (20 + 10) * 2; break; }
return ulMaxStrLen; }
|