6432 lines
191 KiB
C++
6432 lines
191 KiB
C++
// This is a part of the Active Template Library.
|
|
// Copyright (C) 1996-1998 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Active Template Library Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Active Template Library product.
|
|
|
|
#ifndef __ATLDB_H
|
|
#define __ATLDB_H
|
|
|
|
// OLE DB Provider Support
|
|
|
|
// Interface Impl Classes
|
|
//
|
|
// Data Source Object
|
|
//
|
|
// -Mandatory Interfaces:
|
|
// IDBCreateSession
|
|
// IDBInitialize
|
|
// IDBProperties
|
|
// IPersist
|
|
//
|
|
// Session Object
|
|
//
|
|
// -Mandatory Interfaces:
|
|
// IGetDataSource
|
|
// IOpenRowset
|
|
// ISessionProperties
|
|
//
|
|
// -Optional Interfaces:
|
|
// IDBCreateCommand
|
|
// IDBSchemaRowset
|
|
//
|
|
// Rowset Object
|
|
//
|
|
// -Mandatory Interfaces:
|
|
// IAccessor
|
|
// IColumnsInfo
|
|
// IConvertType
|
|
// IRowset
|
|
// IRowsetInfo
|
|
//
|
|
// -Optional Interfaces:
|
|
// IRowsetIdentity
|
|
//
|
|
// Command Object
|
|
//
|
|
// -Mandatory Interfaces:
|
|
// ICommand)
|
|
// IAccessor)
|
|
// ICommandProperties
|
|
// ICommandText - derives from ICommand
|
|
// IColumnsInfo
|
|
// IConvertType
|
|
|
|
#include <oledb.h>
|
|
#include <limits.h>
|
|
#include <oledberr.h>
|
|
#include <msdadc.h>
|
|
#include <atldbcli.h>
|
|
|
|
//Forwards
|
|
template <class T> class CUtlPropInfo;
|
|
class CColumnIds;
|
|
|
|
// Additional Property Flag needed internally
|
|
const int DBPROPFLAGS_CHANGE = 0x40000000;
|
|
|
|
// ------------- STRUCTURE DEFINITIONS --------------------------------
|
|
|
|
struct UPROPVAL
|
|
{
|
|
DBPROPOPTIONS dwOption;
|
|
CColumnIds* pCColumnIds;
|
|
DWORD dwFlags;
|
|
VARIANT vValue;
|
|
};
|
|
|
|
struct UPROPINFO
|
|
{
|
|
DBPROPID dwPropId;
|
|
ULONG ulIDS;
|
|
VARTYPE VarType;
|
|
DBPROPFLAGS dwFlags;
|
|
union
|
|
{
|
|
DWORD_PTR dwVal;
|
|
LPOLESTR szVal;
|
|
};
|
|
DBPROPOPTIONS dwOption;
|
|
};
|
|
|
|
struct UPROP
|
|
{
|
|
ULONG cPropIds;
|
|
UPROPINFO** rgpUPropInfo;
|
|
UPROPVAL* pUPropVal;
|
|
};
|
|
|
|
struct PROPCOLID
|
|
{
|
|
DBID dbidProperty; // The column id information
|
|
DBPROPOPTIONS dwOption;
|
|
VARIANT vValue;
|
|
};
|
|
|
|
typedef PROPCOLID* PPROPCOLID;
|
|
|
|
struct UPROPSET
|
|
{
|
|
const GUID* pPropSet;
|
|
ULONG cUPropInfo;
|
|
UPROPINFO* pUPropInfo;
|
|
DWORD dwFlags;
|
|
};
|
|
|
|
struct ATLBINDINGS
|
|
{
|
|
DBBINDING* pBindings;
|
|
DWORD dwRef;
|
|
DBCOUNTITEM cBindings;
|
|
DBACCESSORFLAGS dwAccessorFlags;
|
|
};
|
|
|
|
struct ATLCOLUMNINFO
|
|
{
|
|
LPOLESTR pwszName;
|
|
ITypeInfo *pTypeInfo;
|
|
DBORDINAL iOrdinal;
|
|
DBCOLUMNFLAGS dwFlags;
|
|
DBLENGTH ulColumnSize;
|
|
DBTYPE wType;
|
|
BYTE bPrecision;
|
|
BYTE bScale;
|
|
DBID columnid;
|
|
DBBYTEOFFSET cbOffset;
|
|
};
|
|
|
|
//
|
|
// The following very large sections of defines are to implement auto determination
|
|
// of Preoperty map constants based on a stringized prop name. There is one set for
|
|
// Type (VT_), one for Init Value, and one for Property flags.
|
|
//
|
|
|
|
#define ABORTPRESERVE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define ACTIVESESSIONS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define APPENDONLY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define ASYNCTXNABORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define ASYNCTXNCOMMIT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define AUTH_CACHE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define AUTH_ENCRYPT_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define AUTH_INTEGRATED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define AUTH_MASK_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define AUTH_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define AUTH_PERSIST_ENCRYPTED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define AUTH_USERID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define BLOCKINGSTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define BOOKMARKS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define BOOKMARKSKIPPED_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define BOOKMARKTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define BYREFACCESSORS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define CACHEDEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define CANFETCHBACKWARDS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define CANHOLDROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define CANSCROLLBACKWARDS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define CATALOGLOCATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define CATALOGTERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define CATALOGUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define CHANGEINSERTEDROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE )
|
|
#define COL_AUTOINCREMENT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define COL_DEFAULT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define COL_DESCRIPTION_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define COL_FIXEDLENGTH_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define COL_NULLABLE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define COL_PRIMARYKEY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define COL_UNIQUE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define COLUMNDEFINITION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define COLUMNRESTRICT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define COMMANDTIMEOUT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define COMMITPRESERVE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define CONCATNULLBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define CURRENTCATALOG_Flags ( DBPROPFLAGS_DATASOURCE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define DATASOURCENAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define DATASOURCEREADONLY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define DBMSNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define DBMSVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define DEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define DELAYSTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define DSOTHREADMODEL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define GROUPBY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define HETEROGENEOUSTABLES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define IAccessor_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IColumnsInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IColumnsRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IConnectionPointContainer_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IConvertType_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowsetChange_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowsetIdentity_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowsetIndex_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowsetInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowsetLocate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowsetResynch_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowsetScroll_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IRowsetUpdate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define ISupportErrorInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define ILockBytes_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define ISequentialStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IStorage_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define IDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define IMMOBILEROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_AUTOUPDATE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_CLUSTERED_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_FILLFACTOR_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_INITIALSIZE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_NULLCOLLATION_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_NULLS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_PRIMARYKEY_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_SORTBOOKMARKS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_TEMPINDEX_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_TYPE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INDEX_UNIQUE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_DATASOURCE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_HWND_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_IMPERSONATION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_LCID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_LOCATION_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_MODE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_PROMPT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_PROTECTION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_PROVIDERSTRING_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define INIT_TIMEOUT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define LITERALBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define LITERALIDENTITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MAXINDEXSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MAXOPENROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MAXPENDINGROWS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MAXROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define MAXROWSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MAXROWSIZEINCLUDESBLOB_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MAXTABLESINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MAYWRITECOLUMN_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define MEMORYUSAGE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define MULTIPLEPARAMSETS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MULTIPLERESULTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MULTIPLESTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define MULTITABLEUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFICATIONPHASES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYCOLUMNSET_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWDELETE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWFIRSTCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWINSERT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWRESYNCH_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWSETRELEASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWSETFETCHPOSITIONCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWUNDOCHANGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWUNDODELETE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWUNDOINSERT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NOTIFYROWUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define NULLCOLLATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define OLEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define ORDERBYCOLUMNSINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define ORDEREDBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define OTHERINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define OTHERUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define OUTPUTPARAMETERAVAILABILITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define OWNINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define OWNUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define PERSISTENTIDTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define PREPAREABORTBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define PREPARECOMMITBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define PROCEDURETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define PROVIDERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define PROVIDEROLEDBVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define PROVIDERVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define QUICKRESTART_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define QUOTEDIDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define REENTRANTEVENTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define REMOVEDELETED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define REPORTMULTIPLECHANGES_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE )
|
|
#define RETURNPENDINGINSERTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define ROWRESTRICT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define ROWSETCONVERSIONSONCOMMAND_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define ROWTHREADMODEL_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define SCHEMATERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define SCHEMAUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define SERVERCURSOR_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define SESS_AUTOCOMMITISOLEVELS_Flags ( DBPROPFLAGS_SESSION | DBPROPFLAGS_READ )
|
|
#define SQLSUPPORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define STRONGIDENTITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define STRUCTUREDSTORAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define SUBQUERIES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define SUPPORTEDTXNDDL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define SUPPORTEDTXNISOLEVELS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define SUPPORTEDTXNISORETAIN_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define TABLETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
#define TBL_TEMPTABLE_Flags ( DBPROPFLAGS_TABLE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define TRANSACTEDOBJECT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ )
|
|
#define UPDATABILITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE )
|
|
#define USERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ )
|
|
|
|
|
|
|
|
#define ABORTPRESERVE_Type VT_BOOL
|
|
#define ACTIVESESSIONS_Type VT_I4
|
|
#define APPENDONLY_Type VT_BOOL
|
|
#define ASYNCTXNABORT_Type VT_BOOL
|
|
#define ASYNCTXNCOMMIT_Type VT_BOOL
|
|
#define AUTH_CACHE_AUTHINFO_Type VT_BOOL
|
|
#define AUTH_ENCRYPT_PASSWORD_Type VT_BOOL
|
|
#define AUTH_INTEGRATED_Type VT_BSTR
|
|
#define AUTH_MASK_PASSWORD_Type VT_BOOL
|
|
#define AUTH_PASSWORD_Type VT_BSTR
|
|
#define AUTH_PERSIST_ENCRYPTED_Type VT_BOOL
|
|
#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Type VT_BOOL
|
|
#define AUTH_USERID_Type VT_BSTR
|
|
#define BLOCKINGSTORAGEOBJECTS_Type VT_BOOL
|
|
#define BOOKMARKS_Type VT_BOOL
|
|
#define BOOKMARKSKIPPED_Type VT_BOOL
|
|
#define BOOKMARKTYPE_Type VT_I4
|
|
#define BYREFACCESSORS_Type VT_BOOL
|
|
#define CACHEDEFERRED_Type VT_BOOL
|
|
#define CANFETCHBACKWARDS_Type VT_BOOL
|
|
#define CANHOLDROWS_Type VT_BOOL
|
|
#define CANSCROLLBACKWARDS_Type VT_BOOL
|
|
#define CATALOGLOCATION_Type VT_I4
|
|
#define CATALOGTERM_Type VT_BSTR
|
|
#define CATALOGUSAGE_Type VT_I4
|
|
#define CHANGEINSERTEDROWS_Type VT_BOOL
|
|
#define COL_AUTOINCREMENT_Type VT_BOOL
|
|
#define COL_DEFAULT_Type VT_BSTR
|
|
#define COL_DESCRIPTION_Type VT_BSTR
|
|
#define COL_FIXEDLENGTH_Type VT_BOOL
|
|
#define COL_NULLABLE_Type VT_BOOL
|
|
#define COL_PRIMARYKEY_Type VT_BOOL
|
|
#define COL_UNIQUE_Type VT_BOOL
|
|
#define COLUMNDEFINITION_Type VT_I4
|
|
#define COLUMNRESTRICT_Type VT_BOOL
|
|
#define COMMANDTIMEOUT_Type VT_I4
|
|
#define COMMITPRESERVE_Type VT_BOOL
|
|
#define CONCATNULLBEHAVIOR_Type VT_I4
|
|
#define CURRENTCATALOG_Type VT_BSTR
|
|
#define DATASOURCENAME_Type VT_BSTR
|
|
#define DATASOURCEREADONLY_Type VT_BOOL
|
|
#define DBMSNAME_Type VT_BSTR
|
|
#define DBMSVER_Type VT_BSTR
|
|
#define DEFERRED_Type VT_BOOL
|
|
#define DELAYSTORAGEOBJECTS_Type VT_BOOL
|
|
#define DSOTHREADMODEL_Type VT_I4
|
|
#define GROUPBY_Type VT_I4
|
|
#define HETEROGENEOUSTABLES_Type VT_I4
|
|
#define IAccessor_Type VT_BOOL
|
|
#define IColumnsInfo_Type VT_BOOL
|
|
#define IColumnsRowset_Type VT_BOOL
|
|
#define IConnectionPointContainer_Type VT_BOOL
|
|
#define IConvertType_Type VT_BOOL
|
|
#define IRowset_Type VT_BOOL
|
|
#define IRowsetChange_Type VT_BOOL
|
|
#define IRowsetIdentity_Type VT_BOOL
|
|
#define IRowsetIndex_Type VT_BOOL
|
|
#define IRowsetInfo_Type VT_BOOL
|
|
#define IRowsetLocate_Type VT_BOOL
|
|
#define IRowsetResynch_Type VT_BOOL
|
|
#define IRowsetScroll_Type VT_BOOL
|
|
#define IRowsetUpdate_Type VT_BOOL
|
|
#define ISupportErrorInfo_Type VT_BOOL
|
|
#define ILockBytes_Type VT_BOOL
|
|
#define ISequentialStream_Type VT_BOOL
|
|
#define IStorage_Type VT_BOOL
|
|
#define IStream_Type VT_BOOL
|
|
#define IDENTIFIERCASE_Type VT_I4
|
|
#define IMMOBILEROWS_Type VT_BOOL
|
|
#define INDEX_AUTOUPDATE_Type VT_BOOL
|
|
#define INDEX_CLUSTERED_Type VT_BOOL
|
|
#define INDEX_FILLFACTOR_Type VT_I4
|
|
#define INDEX_INITIALSIZE_Type VT_I4
|
|
#define INDEX_NULLCOLLATION_Type VT_I4
|
|
#define INDEX_NULLS_Type VT_I4
|
|
#define INDEX_PRIMARYKEY_Type VT_BOOL
|
|
#define INDEX_SORTBOOKMARKS_Type VT_BOOL
|
|
#define INDEX_TEMPINDEX_Type VT_BOOL
|
|
#define INDEX_TYPE_Type VT_I4
|
|
#define INDEX_UNIQUE_Type VT_BOOL
|
|
#define INIT_DATASOURCE_Type VT_BSTR
|
|
#define INIT_HWND_Type VT_I4
|
|
#define INIT_IMPERSONATION_LEVEL_Type VT_I4
|
|
#define INIT_LCID_Type VT_I4
|
|
#define INIT_LOCATION_Type VT_BSTR
|
|
#define INIT_MODE_Type VT_I4
|
|
#define INIT_PROMPT_Type VT_I2
|
|
#define INIT_PROTECTION_LEVEL_Type VT_I4
|
|
#define INIT_PROVIDERSTRING_Type VT_BSTR
|
|
#define INIT_TIMEOUT_Type VT_I4
|
|
#define LITERALBOOKMARKS_Type VT_BOOL
|
|
#define LITERALIDENTITY_Type VT_BOOL
|
|
#define MAXINDEXSIZE_Type VT_I4
|
|
#define MAXOPENROWS_Type VT_I4
|
|
#define MAXPENDINGROWS_Type VT_I4
|
|
#define MAXROWS_Type VT_I4
|
|
#define MAXROWSIZE_Type VT_I4
|
|
#define MAXROWSIZEINCLUDESBLOB_Type VT_BOOL
|
|
#define MAXTABLESINSELECT_Type VT_I4
|
|
#define MAYWRITECOLUMN_Type VT_BOOL
|
|
#define MEMORYUSAGE_Type VT_I4
|
|
#define MULTIPLEPARAMSETS_Type VT_BOOL
|
|
#define MULTIPLERESULTS_Type VT_I4
|
|
#define MULTIPLESTORAGEOBJECTS_Type VT_BOOL
|
|
#define MULTITABLEUPDATE_Type VT_BOOL
|
|
#define NOTIFICATIONPHASES_Type VT_I4
|
|
#define NOTIFYCOLUMNSET_Type VT_I4
|
|
#define NOTIFYROWDELETE_Type VT_I4
|
|
#define NOTIFYROWFIRSTCHANGE_Type VT_I4
|
|
#define NOTIFYROWINSERT_Type VT_I4
|
|
#define NOTIFYROWRESYNCH_Type VT_I4
|
|
#define NOTIFYROWSETRELEASE_Type VT_I4
|
|
#define NOTIFYROWSETFETCHPOSITIONCHANGE_Type VT_I4
|
|
#define NOTIFYROWUNDOCHANGE_Type VT_I4
|
|
#define NOTIFYROWUNDODELETE_Type VT_I4
|
|
#define NOTIFYROWUNDOINSERT_Type VT_I4
|
|
#define NOTIFYROWUPDATE_Type VT_I4
|
|
#define NULLCOLLATION_Type VT_I4
|
|
#define OLEOBJECTS_Type VT_I4
|
|
#define ORDERBYCOLUMNSINSELECT_Type VT_BOOL
|
|
#define ORDEREDBOOKMARKS_Type VT_BOOL
|
|
#define OTHERINSERT_Type VT_BOOL
|
|
#define OTHERUPDATEDELETE_Type VT_BOOL
|
|
#define OUTPUTPARAMETERAVAILABILITY_Type VT_I4
|
|
#define OWNINSERT_Type VT_BOOL
|
|
#define OWNUPDATEDELETE_Type VT_BOOL
|
|
#define PERSISTENTIDTYPE_Type VT_I4
|
|
#define PREPAREABORTBEHAVIOR_Type VT_I4
|
|
#define PREPARECOMMITBEHAVIOR_Type VT_I4
|
|
#define PROCEDURETERM_Type VT_BSTR
|
|
#define PROVIDERNAME_Type VT_BSTR
|
|
#define PROVIDEROLEDBVER_Type VT_BSTR
|
|
#define PROVIDERVER_Type VT_BSTR
|
|
#define QUICKRESTART_Type VT_BOOL
|
|
#define QUOTEDIDENTIFIERCASE_Type VT_I4
|
|
#define REENTRANTEVENTS_Type VT_BOOL
|
|
#define REMOVEDELETED_Type VT_BOOL
|
|
#define REPORTMULTIPLECHANGES_Type VT_BOOL
|
|
#define RETURNPENDINGINSERTS_Type VT_BOOL
|
|
#define ROWRESTRICT_Type VT_BOOL
|
|
#define ROWSETCONVERSIONSONCOMMAND_Type VT_BOOL
|
|
#define ROWTHREADMODEL_Type VT_I4
|
|
#define SCHEMATERM_Type VT_BSTR
|
|
#define SCHEMAUSAGE_Type VT_I4
|
|
#define SERVERCURSOR_Type VT_BOOL
|
|
#define SESS_AUTOCOMMITISOLEVELS_Type VT_I4
|
|
#define SQLSUPPORT_Type VT_I4
|
|
#define STRONGIDENTITY_Type VT_BOOL
|
|
#define STRUCTUREDSTORAGE_Type VT_I4
|
|
#define SUBQUERIES_Type VT_I4
|
|
#define SUPPORTEDTXNDDL_Type VT_I4
|
|
#define SUPPORTEDTXNISOLEVELS_Type VT_I4
|
|
#define SUPPORTEDTXNISORETAIN_Type VT_I4
|
|
#define TABLETERM_Type VT_BSTR
|
|
#define TBL_TEMPTABLE_Type VT_BOOL
|
|
#define TRANSACTEDOBJECT_Type VT_BOOL
|
|
#define UPDATABILITY_Type VT_I4
|
|
#define USERNAME_Type VT_BSTR
|
|
|
|
|
|
|
|
#define ABORTPRESERVE_Value VARIANT_FALSE
|
|
#define ACTIVESESSIONS_Value 0
|
|
#define APPENDONLY_Value VARIANT_FALSE
|
|
#define ASYNCTXNABORT_Value VARIANT_FALSE
|
|
#define ASYNCTXNCOMMIT_Value VARIANT_FALSE
|
|
#define AUTH_CACHE_AUTHINFO_Value VARIANT_FALSE
|
|
#define AUTH_ENCRYPT_PASSWORD_Value VARIANT_FALSE
|
|
#define AUTH_INTEGRATED_Value OLESTR("")
|
|
#define AUTH_MASK_PASSWORD_Value VARIANT_FALSE
|
|
#define AUTH_PASSWORD_Value OLESTR("")
|
|
#define AUTH_PERSIST_ENCRYPTED_Value VARIANT_FALSE
|
|
#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Value VARIANT_FALSE
|
|
#define AUTH_USERID_Value OLESTR("")
|
|
#define BLOCKINGSTORAGEOBJECTS_Value VARIANT_FALSE
|
|
#define BOOKMARKS_Value VARIANT_FALSE
|
|
#define BOOKMARKSKIPPED_Value VARIANT_FALSE
|
|
#define BOOKMARKTYPE_Value 0
|
|
#define BYREFACCESSORS_Value VARIANT_FALSE
|
|
#define CACHEDEFERRED_Value VARIANT_FALSE
|
|
#define CANFETCHBACKWARDS_Value VARIANT_TRUE
|
|
#define CANHOLDROWS_Value VARIANT_TRUE
|
|
#define CANSCROLLBACKWARDS_Value VARIANT_TRUE
|
|
#define CATALOGLOCATION_Value 0
|
|
#define CATALOGTERM_Value OLESTR("")
|
|
#define CATALOGUSAGE_Value 0
|
|
#define CHANGEINSERTEDROWS_Value VARIANT_FALSE
|
|
#define COL_AUTOINCREMENT_Value VARIANT_FALSE
|
|
#define COL_DEFAULT_Value OLESTR("")
|
|
#define COL_DESCRIPTION_Value OLESTR("")
|
|
#define COL_FIXEDLENGTH_Value VARIANT_FALSE
|
|
#define COL_NULLABLE_Value VARIANT_FALSE
|
|
#define COL_PRIMARYKEY_Value VARIANT_FALSE
|
|
#define COL_UNIQUE_Value VARIANT_FALSE
|
|
#define COLUMNDEFINITION_Value 0
|
|
#define COLUMNRESTRICT_Value VARIANT_FALSE
|
|
#define COMMANDTIMEOUT_Value 0
|
|
#define COMMITPRESERVE_Value VARIANT_FALSE
|
|
#define CONCATNULLBEHAVIOR_Value 0
|
|
#define CURRENTCATALOG_Value OLESTR("")
|
|
#define DATASOURCENAME_Value OLESTR("")
|
|
#define DATASOURCEREADONLY_Value VARIANT_TRUE
|
|
#define DBMSNAME_Value OLESTR("")
|
|
#define DBMSVER_Value OLESTR("")
|
|
#define DEFERRED_Value VARIANT_FALSE
|
|
#define DELAYSTORAGEOBJECTS_Value VARIANT_FALSE
|
|
#define DSOTHREADMODEL_Value DBPROPVAL_RT_APTMTTHREAD
|
|
#define GROUPBY_Value 0
|
|
#define HETEROGENEOUSTABLES_Value 0
|
|
#define IAccessor_Value VARIANT_TRUE
|
|
#define IColumnsInfo_Value VARIANT_TRUE
|
|
#define IColumnsRowset_Value VARIANT_FALSE
|
|
#define IConnectionPointContainer_Value VARIANT_FALSE
|
|
#define IConvertType_Value VARIANT_TRUE
|
|
#define IRowset_Value VARIANT_TRUE
|
|
#define IRowsetChange_Value VARIANT_FALSE
|
|
#define IRowsetIdentity_Value VARIANT_TRUE
|
|
#define IRowsetIndex_Value VARIANT_FALSE
|
|
#define IRowsetInfo_Value VARIANT_TRUE
|
|
#define IRowsetLocate_Value VARIANT_FALSE
|
|
#define IRowsetResynch_Value VARIANT_FALSE
|
|
#define IRowsetScroll_Value VARIANT_FALSE
|
|
#define IRowsetUpdate_Value VARIANT_FALSE
|
|
#define ISupportErrorInfo_Value VARIANT_FALSE
|
|
#define ILockBytes_Value VARIANT_FALSE
|
|
#define ISequentialStream_Value VARIANT_FALSE
|
|
#define IStorage_Value VARIANT_FALSE
|
|
#define IStream_Value VARIANT_FALSE
|
|
#define IDENTIFIERCASE_Value 0
|
|
#define IMMOBILEROWS_Value VARIANT_FALSE
|
|
#define INDEX_AUTOUPDATE_Value VARIANT_FALSE
|
|
#define INDEX_CLUSTERED_Value VARIANT_FALSE
|
|
#define INDEX_FILLFACTOR_Value 0
|
|
#define INDEX_INITIALSIZE_Value 0
|
|
#define INDEX_NULLCOLLATION_Value 0
|
|
#define INDEX_NULLS_Value 0
|
|
#define INDEX_PRIMARYKEY_Value VARIANT_FALSE
|
|
#define INDEX_SORTBOOKMARKS_Value VARIANT_FALSE
|
|
#define INDEX_TEMPINDEX_Value VARIANT_FALSE
|
|
#define INDEX_TYPE_Value 0
|
|
#define INDEX_UNIQUE_Value VARIANT_FALSE
|
|
#define INIT_DATASOURCE_Value OLESTR("")
|
|
#define INIT_HWND_Value 0
|
|
#define INIT_IMPERSONATION_LEVEL_Value 0
|
|
#define INIT_LCID_Value 0
|
|
#define INIT_LOCATION_Value OLESTR("")
|
|
#define INIT_MODE_Value 0
|
|
#define INIT_PROMPT_Value VT_I2
|
|
#define INIT_PROTECTION_LEVEL_Value 0
|
|
#define INIT_PROVIDERSTRING_Value OLESTR("")
|
|
#define INIT_TIMEOUT_Value 0
|
|
#define LITERALBOOKMARKS_Value VARIANT_FALSE
|
|
#define LITERALIDENTITY_Value VARIANT_FALSE
|
|
#define MAXINDEXSIZE_Value 0
|
|
#define MAXOPENROWS_Value 0
|
|
#define MAXPENDINGROWS_Value 0
|
|
#define MAXROWS_Value 0
|
|
#define MAXROWSIZE_Value 0
|
|
#define MAXROWSIZEINCLUDESBLOB_Value VARIANT_FALSE
|
|
#define MAXTABLESINSELECT_Value 0
|
|
#define MAYWRITECOLUMN_Value VARIANT_FALSE
|
|
#define MEMORYUSAGE_Value 0
|
|
#define MULTIPLEPARAMSETS_Value VARIANT_FALSE
|
|
#define MULTIPLERESULTS_Value 0
|
|
#define MULTIPLESTORAGEOBJECTS_Value VARIANT_FALSE
|
|
#define MULTITABLEUPDATE_Value VARIANT_FALSE
|
|
#define NOTIFICATIONPHASES_Value 0
|
|
#define NOTIFYCOLUMNSET_Value 0
|
|
#define NOTIFYROWDELETE_Value 0
|
|
#define NOTIFYROWFIRSTCHANGE_Value 0
|
|
#define NOTIFYROWINSERT_Value 0
|
|
#define NOTIFYROWRESYNCH_Value 0
|
|
#define NOTIFYROWSETRELEASE_Value 0
|
|
#define NOTIFYROWSETFETCHPOSITIONCHANGE_Value 0
|
|
#define NOTIFYROWUNDOCHANGE_Value 0
|
|
#define NOTIFYROWUNDODELETE_Value 0
|
|
#define NOTIFYROWUNDOINSERT_Value 0
|
|
#define NOTIFYROWUPDATE_Value 0
|
|
#define NULLCOLLATION_Value 0
|
|
#define OLEOBJECTS_Value 0
|
|
#define ORDERBYCOLUMNSINSELECT_Value VARIANT_FALSE
|
|
#define ORDEREDBOOKMARKS_Value VARIANT_FALSE
|
|
#define OTHERINSERT_Value VARIANT_FALSE
|
|
#define OTHERUPDATEDELETE_Value VARIANT_FALSE
|
|
#define OUTPUTPARAMETERAVAILABILITY_Value 0
|
|
#define OWNINSERT_Value VARIANT_FALSE
|
|
#define OWNUPDATEDELETE_Value VARIANT_FALSE
|
|
#define PERSISTENTIDTYPE_Value 0
|
|
#define PREPAREABORTBEHAVIOR_Value 0
|
|
#define PREPARECOMMITBEHAVIOR_Value 0
|
|
#define PROCEDURETERM_Value OLESTR("")
|
|
#define PROVIDERNAME_Value OLESTR("")
|
|
#define PROVIDEROLEDBVER_Value OLESTR("2.0")
|
|
#define PROVIDERVER_Value OLESTR("")
|
|
#define QUICKRESTART_Value VARIANT_FALSE
|
|
#define QUOTEDIDENTIFIERCASE_Value 0
|
|
#define REENTRANTEVENTS_Value VARIANT_FALSE
|
|
#define REMOVEDELETED_Value VARIANT_FALSE
|
|
#define REPORTMULTIPLECHANGES_Value VARIANT_FALSE
|
|
#define RETURNPENDINGINSERTS_Value VARIANT_FALSE
|
|
#define ROWRESTRICT_Value VARIANT_FALSE
|
|
#define ROWSETCONVERSIONSONCOMMAND_Value VARIANT_TRUE
|
|
#define ROWTHREADMODEL_Value 0
|
|
#define SCHEMATERM_Value OLESTR("")
|
|
#define SCHEMAUSAGE_Value 0
|
|
#define SERVERCURSOR_Value VARIANT_FALSE
|
|
#define SESS_AUTOCOMMITISOLEVELS_Value 0
|
|
#define SQLSUPPORT_Value 0
|
|
#define STRONGIDENTITY_Value VARIANT_FALSE
|
|
#define STRUCTUREDSTORAGE_Value 0
|
|
#define SUBQUERIES_Value 0
|
|
#define SUPPORTEDTXNDDL_Value 0
|
|
#define SUPPORTEDTXNISOLEVELS_Value 0
|
|
#define SUPPORTEDTXNISORETAIN_Value 0
|
|
#define TABLETERM_Value OLESTR("")
|
|
#define TBL_TEMPTABLE_Value VARIANT_FALSE
|
|
#define TRANSACTEDOBJECT_Value VARIANT_FALSE
|
|
#define UPDATABILITY_Value 0
|
|
#define USERNAME_Value OLESTR("")
|
|
|
|
|
|
#define OUT_OF_LINE virtual
|
|
|
|
#define BEGIN_PROPSET_MAP(Class) \
|
|
static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL)) \
|
|
{ \
|
|
typedef Class _PropSetClass; \
|
|
ULONG& cElemsMax = *pcElemPerSupported; \
|
|
cElemsMax = 0; \
|
|
int nCurProp = 0; \
|
|
int cRemainder = 0; \
|
|
cRemainder;
|
|
|
|
#define BEGIN_PROPERTY_SET_EX(guid, flags) \
|
|
if (pNumPropSets != NULL) \
|
|
{ \
|
|
pSet[nCurProp].pPropSet = &guid; \
|
|
pSet[nCurProp].dwFlags = flags; \
|
|
} \
|
|
static const UPROPINFO aProperty##guid[] = \
|
|
{
|
|
|
|
#define BEGIN_PROPERTY_SET(guid) BEGIN_PROPERTY_SET_EX(guid, 0)
|
|
|
|
#define PROPERTY_INFO_ENTRY_EX(dwPropID, vt, dwFlags, value, options) DBPROP_##dwPropID, IDS_DBPROP_##dwPropID, vt, dwFlags, (DWORD_PTR)value, (DBPROPOPTIONS)options,
|
|
|
|
#define PROPERTY_INFO_ENTRY_VALUE(dwPropID, value) PROPERTY_INFO_ENTRY_EX(dwPropID, dwPropID##_Type, ##dwPropID##_Flags, value, 0)
|
|
|
|
#define PROPERTY_INFO_ENTRY(dwPropID) PROPERTY_INFO_ENTRY_VALUE(dwPropID, dwPropID##_Value)
|
|
|
|
|
|
#define END_PROPERTY_SET(guid) \
|
|
}; \
|
|
if (pNumPropSets != NULL) \
|
|
{ \
|
|
pSet[nCurProp].pUPropInfo = (UPROPINFO*)aProperty##guid; \
|
|
pSet[nCurProp].cUPropInfo = sizeof(aProperty##guid) / sizeof(UPROPINFO); \
|
|
cRemainder = (pSet[nCurProp].cUPropInfo % 32) ? 1 : 0; \
|
|
if (cElemsMax < (pSet[nCurProp].cUPropInfo / 32 + cRemainder)) \
|
|
{ \
|
|
cElemsMax = (pSet[nCurProp].cUPropInfo / 32 + cRemainder); \
|
|
} \
|
|
} \
|
|
nCurProp++;
|
|
|
|
#define CHAIN_PROPERTY_SET(ChainClass) \
|
|
ULONG cPropSets##ChainClass, cElsSupported##ChainClass; \
|
|
int cSets##ChainClass = (int)(DWORD_PTR)ChainClass::_GetPropSet(NULL, &cElsSupported##ChainClass); \
|
|
if (pNumPropSets != NULL) \
|
|
{ \
|
|
UPROPSET* pSetA = (UPROPSET*)_alloca(sizeof(UPROPSET)*cSets##ChainClass); \
|
|
UPROPSET* pSetTemp = ChainClass::_GetPropSet(&cPropSets##ChainClass, &cElsSupported##ChainClass, pSetA); \
|
|
cElemsMax = (cElemsMax < cElsSupported##ChainClass) ? cElsSupported##ChainClass : cElemsMax; \
|
|
ATLASSERT(pSetTemp); \
|
|
for (ULONG iSet = nCurProp; iSet < nCurProp+cPropSets##ChainClass; iSet++) \
|
|
{ \
|
|
pSet[iSet].pPropSet = pSetTemp[iSet-nCurProp].pPropSet; \
|
|
pSet[iSet].dwFlags = pSetTemp[iSet-nCurProp].dwFlags; \
|
|
pSet[iSet].pUPropInfo = pSetTemp[iSet-nCurProp].pUPropInfo; \
|
|
pSet[iSet].cUPropInfo = pSetTemp[iSet-nCurProp].cUPropInfo; \
|
|
} \
|
|
} \
|
|
nCurProp += cSets##ChainClass;
|
|
|
|
#define END_PROPSET_MAP() \
|
|
if (pNumPropSets != NULL) \
|
|
{ \
|
|
if (IsEqualGUID(*pguidSet, GUID_NULL)) \
|
|
{ \
|
|
*pNumPropSets = nCurProp; \
|
|
return pSet; \
|
|
} \
|
|
else \
|
|
{ \
|
|
*pNumPropSets = 1; \
|
|
UINT i = 0; \
|
|
for (; i < sizeof(pSet)/sizeof(UPROPSET) && IsEqualGUID(*(pSet[i].pPropSet), *pguidSet); i++); \
|
|
return (i == sizeof(pSet)/sizeof(UPROPSET)) ? &pSet[0] : &pSet[i]; \
|
|
} \
|
|
} \
|
|
return (UPROPSET*)(DWORD_PTR)nCurProp; \
|
|
}
|
|
|
|
|
|
// For DataSource flags IDBInitialize::m_dwStatus
|
|
enum DATASOURCE_FLAGS {
|
|
DSF_MASK_INIT = 0xFFFFF00F, // Mask for stuff lasting over init/uninit.
|
|
DSF_PERSIST_DIRTY = 0x00000001, // Set if init string changes.
|
|
DSF_INITIALIZED = 0x00000010, // Have we been initialized.
|
|
};
|
|
|
|
|
|
#define DBID_USE_GUID_OR_PGUID(e) \
|
|
((1<<(e)) & \
|
|
( 1<<DBKIND_GUID \
|
|
| 1<<DBKIND_GUID_NAME \
|
|
| 1<<DBKIND_GUID_PROPID \
|
|
| 1<<DBKIND_PGUID_NAME \
|
|
| 1<<DBKIND_PGUID_PROPID ))
|
|
|
|
#define DBID_USE_GUID(e) \
|
|
((1<<(e)) & \
|
|
( 1<<DBKIND_GUID \
|
|
| 1<<DBKIND_GUID_NAME \
|
|
| 1<<DBKIND_GUID_PROPID ))
|
|
|
|
#define DBID_USE_PGUID(e) \
|
|
((1<<(e)) & \
|
|
( 1<<DBKIND_PGUID_NAME \
|
|
| 1<<DBKIND_PGUID_PROPID ))
|
|
|
|
#define DBID_USE_NAME(e) \
|
|
((1<<(e)) & \
|
|
( 1<<DBKIND_NAME \
|
|
| 1<<DBKIND_GUID_NAME \
|
|
| 1<<DBKIND_PGUID_NAME ))
|
|
|
|
#define DBID_USE_PROPID(e) \
|
|
((1<<(e)) & \
|
|
( 1<<DBKIND_PROPID \
|
|
| 1<<DBKIND_GUID_PROPID \
|
|
| 1<<DBKIND_PGUID_PROPID ))
|
|
|
|
// Bookmark can be either guid or pguid.
|
|
#define DBID_IS_BOOKMARK(dbid) \
|
|
( DBID_USE_GUID(dbid.eKind) && dbid.uGuid.guid == DBCOL_SPECIALCOL \
|
|
|| DBID_USE_PGUID(dbid.eKind) && *dbid.uGuid.pguid == DBCOL_SPECIALCOL )
|
|
|
|
#define DivDword(dw) (dw >> 5) // dw / 32 = dw / (sizeof(DWORD)*8)
|
|
#define ModDword(dw) (dw & (32-1)) // dw % 32
|
|
#define DwordSizeofBits(nBits) (nBits/32+1) // Use in array declarations
|
|
#define CLEARBITARRAY( rgdwFlags ) memset( rgdwFlags, 0, sizeof(rgdwFlags) )
|
|
|
|
template <class T>
|
|
BOOL InRange(T& val, T& valMin, T& valMax)
|
|
{
|
|
return ( valMin <= val && val <= valMax );
|
|
}
|
|
// Implementation Class
|
|
class CBitFieldOps
|
|
{
|
|
public:
|
|
void SETBIT( DWORD rgdwFlags[], const DWORD dwBit )
|
|
{
|
|
rgdwFlags[DivDword(dwBit)] |= 1 << ModDword(dwBit);
|
|
}
|
|
|
|
void CLEARBIT( DWORD rgdwFlags[], const DWORD dwBit )
|
|
{
|
|
rgdwFlags[DivDword(dwBit)] &= ~( 1 << ModDword(dwBit) );
|
|
}
|
|
|
|
DWORD TESTBIT( const DWORD rgdwFlags[], const DWORD dwBit )
|
|
{
|
|
//old//Note: Not {0,1}, but from {0...2^32-1}.
|
|
// Note: Now returns {0,1}.
|
|
return ( rgdwFlags[DivDword(dwBit)] & ( 1 << ModDword(dwBit) ) ) != 0;
|
|
}
|
|
};
|
|
|
|
// Implementation Class
|
|
class CDBIDOps
|
|
{
|
|
public:
|
|
HRESULT CompareDBIDs(const DBID* pdbid1, const DBID* pdbid2)
|
|
{
|
|
// Array of valid eKind matches, in addition to matching exactly.
|
|
static BYTE s_rgbKind[] =
|
|
{
|
|
DBKIND_PGUID_NAME, // DBKIND_GUID_NAME
|
|
DBKIND_PGUID_PROPID, // DBKIND_GUID_PROPID
|
|
DBKIND_NAME, // DBKIND_NAME
|
|
DBKIND_GUID_NAME, // DBKIND_PGUID_NAME
|
|
DBKIND_GUID_PROPID, // DBKIND_PGUID_PROPID
|
|
DBKIND_PROPID, // DBKIND_PROPID
|
|
DBKIND_GUID // DBKIND_GUID
|
|
};
|
|
|
|
if( !pdbid1 || !pdbid2 )
|
|
return S_FALSE;
|
|
|
|
// Assume a match, and discard early if we can.
|
|
if (!InRange(pdbid2->eKind, (DWORD)0, (DWORD)(sizeof(s_rgbKind)/sizeof(*s_rgbKind))))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Column ID out of Range\n");
|
|
return E_FAIL;
|
|
}
|
|
if (pdbid1->eKind != pdbid2->eKind
|
|
&& pdbid1->eKind != s_rgbKind[pdbid2->eKind])
|
|
return S_FALSE;
|
|
|
|
if (DBID_USE_GUID_OR_PGUID(pdbid1->eKind))
|
|
{
|
|
if (!DBID_USE_GUID_OR_PGUID(pdbid2->eKind))
|
|
return S_FALSE;
|
|
// Compare GUIDs.
|
|
// Note that _GUID_ is equivalent to _PGUID_.
|
|
if (!InlineIsEqualGUID(
|
|
DBID_USE_PGUID(pdbid1->eKind) ? *(pdbid1->uGuid.pguid) : pdbid1->uGuid.guid,
|
|
DBID_USE_PGUID(pdbid2->eKind) ? *(pdbid2->uGuid.pguid) : pdbid2->uGuid.guid ))
|
|
return S_FALSE;
|
|
}
|
|
if (DBID_USE_NAME(pdbid1->eKind))
|
|
{
|
|
if (!DBID_USE_NAME(pdbid2->eKind))
|
|
return S_FALSE;
|
|
// Compare names.
|
|
// Need to check if 1 is null and the other is not.
|
|
if ( ((pdbid1->uName.pwszName == NULL) &&
|
|
(pdbid2->uName.pwszName != NULL)) ||
|
|
((pdbid1->uName.pwszName != NULL) &&
|
|
(pdbid2->uName.pwszName == NULL)) )
|
|
return S_FALSE;
|
|
// Since the above check does not rule out both being null, which is
|
|
// a valid comparison, and wcscmp will GPF if they were, we need
|
|
// to check for valid pointers
|
|
if( pdbid1->uName.pwszName && pdbid2->uName.pwszName )
|
|
{
|
|
// Assume null-terminated.
|
|
// Assume LCID match is OK (note diff with lstrcmp(), CompareString().)
|
|
if (wcscmp(pdbid1->uName.pwszName, pdbid2->uName.pwszName) != 0)
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
if (DBID_USE_PROPID(pdbid1->eKind))
|
|
{
|
|
if (!DBID_USE_PROPID(pdbid2->eKind))
|
|
return S_FALSE;
|
|
// Compare PROPID.
|
|
if (pdbid1->uName.ulPropid != pdbid2->uName.ulPropid)
|
|
return S_FALSE;
|
|
}
|
|
|
|
// No reason to discard, so must have matched each field successfully.
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT IsValidDBID(const DBID* pdbid1)
|
|
{
|
|
ATLASSERT( pdbid1 );
|
|
|
|
if( pdbid1 &&
|
|
((pdbid1->eKind == DBKIND_GUID_NAME) ||
|
|
(pdbid1->eKind == DBKIND_GUID_PROPID) ||
|
|
(pdbid1->eKind == DBKIND_NAME) ||
|
|
(pdbid1->eKind == DBKIND_PGUID_NAME) ||
|
|
(pdbid1->eKind == DBKIND_PGUID_PROPID) ||
|
|
(pdbid1->eKind == DBKIND_PROPID) ||
|
|
(pdbid1->eKind == DBKIND_GUID)) )
|
|
return S_OK;
|
|
else
|
|
return S_FALSE;
|
|
}
|
|
HRESULT CopyDBIDs(DBID* pdbidDest, const DBID* pdbidSrc)
|
|
{
|
|
size_t cwchBuffer;
|
|
|
|
ATLASSERT( pdbidDest || pdbidSrc );
|
|
|
|
if( !pdbidDest || !pdbidSrc )
|
|
return S_FALSE;
|
|
|
|
// Save eKind
|
|
pdbidDest->eKind = pdbidSrc->eKind;
|
|
|
|
switch( pdbidSrc->eKind )
|
|
{
|
|
|
|
case DBKIND_GUID_NAME:
|
|
pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
|
|
cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
|
|
cwchBuffer++;
|
|
pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
|
|
if( pdbidDest->uName.pwszName )
|
|
memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
|
|
else
|
|
return E_OUTOFMEMORY;
|
|
break;
|
|
|
|
case DBKIND_GUID_PROPID:
|
|
pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
|
|
pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
|
|
break;
|
|
case DBKIND_NAME:
|
|
cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
|
|
cwchBuffer++;
|
|
pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
|
|
if( pdbidDest->uName.pwszName )
|
|
memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
|
|
else
|
|
return E_OUTOFMEMORY;
|
|
break;
|
|
case DBKIND_PGUID_NAME:
|
|
pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID));
|
|
if( pdbidDest->uGuid.pguid )
|
|
{
|
|
*(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid);
|
|
cwchBuffer = ocslen(pdbidSrc->uName.pwszName);
|
|
cwchBuffer++;
|
|
pdbidDest->uName.pwszName = (PWSTR)CoTaskMemAlloc(cwchBuffer * sizeof(WCHAR));
|
|
if( pdbidDest->uName.pwszName )
|
|
{
|
|
memcpy(pdbidDest->uName.pwszName, pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR));
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
CoTaskMemFree(pdbidDest->uGuid.pguid);
|
|
pdbidDest->uGuid.pguid = NULL;
|
|
}
|
|
}
|
|
return E_OUTOFMEMORY;
|
|
case DBKIND_PGUID_PROPID:
|
|
pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID));
|
|
if( pdbidDest->uGuid.pguid )
|
|
*(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid);
|
|
else
|
|
return E_OUTOFMEMORY;
|
|
pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
|
|
break;
|
|
case DBKIND_PROPID:
|
|
pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid;
|
|
break;
|
|
case DBKIND_GUID:
|
|
pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid;
|
|
break;
|
|
default:
|
|
ATLASSERT(L"Unhandled dbid1.ekind");
|
|
return S_FALSE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
static GUID* GetDBIDpGuid(DBID& dbid)
|
|
{
|
|
GUID* pGuid;
|
|
switch (dbid.eKind)
|
|
{
|
|
case DBKIND_PGUID_NAME:
|
|
case DBKIND_PGUID_PROPID:
|
|
pGuid = dbid.uGuid.pguid;
|
|
break;
|
|
case DBKIND_GUID_NAME:
|
|
case DBKIND_GUID_PROPID:
|
|
case DBKIND_GUID:
|
|
pGuid = &(dbid.uGuid.guid);
|
|
break;
|
|
default:
|
|
pGuid = NULL;
|
|
}
|
|
|
|
return pGuid;
|
|
}
|
|
static ULONG GetPropIDFromDBID(DBID& dbid)
|
|
{
|
|
switch (dbid.eKind)
|
|
{
|
|
case DBKIND_GUID_PROPID:
|
|
case DBKIND_PGUID_PROPID:
|
|
case DBKIND_PROPID:
|
|
return dbid.uName.ulPropid;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
void FreeDBIDs(DBID* pdbidSrc)
|
|
{
|
|
switch( pdbidSrc->eKind )
|
|
{
|
|
|
|
case DBKIND_GUID_NAME:
|
|
CoTaskMemFree(pdbidSrc->uName.pwszName);
|
|
break;
|
|
case DBKIND_NAME:
|
|
CoTaskMemFree(pdbidSrc->uName.pwszName);
|
|
break;
|
|
case DBKIND_PGUID_NAME:
|
|
CoTaskMemFree(pdbidSrc->uGuid.pguid);
|
|
CoTaskMemFree(pdbidSrc->uName.pwszName);
|
|
break;
|
|
case DBKIND_PGUID_PROPID:
|
|
CoTaskMemFree(pdbidSrc->uGuid.pguid);
|
|
break;
|
|
case DBKIND_GUID_PROPID:
|
|
case DBKIND_PROPID:
|
|
case DBKIND_GUID:
|
|
break;
|
|
default:
|
|
ATLASSERT(L"Unhandled dbid1.ekind");
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
extern "C" const CLSID CLSID_DataConvert;
|
|
|
|
class CConvertHelper
|
|
{
|
|
public:
|
|
CConvertHelper() {}
|
|
HRESULT FinalConstruct()
|
|
{
|
|
HRESULT hr = ::CoCreateInstance(CLSID_DataConvert, NULL, CLSCTX_INPROC_SERVER, IID_IDataConvert, (void**)&m_spConvert);
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
// Check to see if the data conversion routine is 2.0 capable, if so. Initialize
|
|
// the conversion routine to be 2.0.
|
|
DCINFO rgInfo[] = {{DCINFOTYPE_VERSION, {VT_UI4, 0, 0, 0, 0x0}}};
|
|
CComPtr<IDCInfo> spIDCInfo;
|
|
|
|
hr = m_spConvert->QueryInterface(&spIDCInfo);
|
|
if (hr == S_OK)
|
|
{
|
|
V_UI4(&rgInfo->vData) = 0x200; // OLEDB Version 02.00
|
|
spIDCInfo->SetInfo(1, rgInfo);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
CComPtr<IDataConvert> m_spConvert;
|
|
};
|
|
|
|
// IDBCreateSessionImpl
|
|
template <class T, class SessionClass>
|
|
class ATL_NO_VTABLE IDBCreateSessionImpl : public IDBCreateSession
|
|
{
|
|
public:
|
|
STDMETHOD(CreateSession)(IUnknown *pUnkOuter,
|
|
REFIID riid,
|
|
IUnknown **ppDBSession)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateSessionImpl::CreateSession\n");
|
|
if (ppDBSession == NULL)
|
|
return E_INVALIDARG;
|
|
T* pT = (T*)this;
|
|
if (!(pT->m_dwStatus & DSF_INITIALIZED))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateSessionImpl::CreateSession : Error not initialized\n");
|
|
*ppDBSession = NULL;
|
|
return E_UNEXPECTED;
|
|
}
|
|
CComPolyObject<SessionClass> *pSession;
|
|
|
|
// You can't QI for an interface other than IUnknown when aggregating
|
|
// and creating the object. You might ask for your own interface,
|
|
// which would be bad. Note, we return DB_E_NOAGGREGATION instead of
|
|
// CLASS_E_NOAGGREGATION due to OLE DB constraints.
|
|
if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid))
|
|
return DB_E_NOAGGREGATION;
|
|
|
|
HRESULT hr = CComPolyObject<SessionClass>::CreateInstance(pUnkOuter, &pSession);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CComPtr<IObjectWithSite> spCreator;
|
|
hr = pSession->QueryInterface(IID_IObjectWithSite, (void**)&spCreator);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
spCreator->SetSite(this);
|
|
hr = pSession->QueryInterface(riid, (void**)ppDBSession);
|
|
}
|
|
else
|
|
delete pSession;
|
|
}
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
// IDBInitializeImpl
|
|
template <class T>
|
|
class ATL_NO_VTABLE IDBInitializeImpl : public IDBInitialize
|
|
{
|
|
public:
|
|
IDBInitializeImpl()
|
|
{
|
|
m_dwStatus = 0;
|
|
m_pCUtlPropInfo = NULL;
|
|
m_cSessionsOpen = 0;
|
|
}
|
|
~IDBInitializeImpl()
|
|
{
|
|
delete m_pCUtlPropInfo;
|
|
}
|
|
|
|
STDMETHOD(Uninitialize)(void)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Uninitialize\n");
|
|
T* pT = (T*)this;
|
|
pT->Lock();
|
|
if (pT->m_cSessionsOpen != 0)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Uninitialized called with Open Sessions\n");
|
|
return DB_E_OBJECTOPEN;
|
|
}
|
|
delete m_pCUtlPropInfo;
|
|
m_pCUtlPropInfo = NULL;
|
|
pT->m_dwStatus |= DSF_PERSIST_DIRTY;
|
|
pT->m_dwStatus &= DSF_MASK_INIT; // Clear all non-init flags.
|
|
pT->Unlock();
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
LONG m_cSessionsOpen;
|
|
DWORD m_dwStatus;
|
|
CUtlPropInfo<T>* m_pCUtlPropInfo;
|
|
|
|
STDMETHOD(Initialize)(void)
|
|
{
|
|
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize\n");
|
|
T *pT = (T*)(this);
|
|
T::ObjectLock lock(pT);
|
|
HRESULT hr;
|
|
if (pT->m_dwStatus & DSF_INITIALIZED)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : Already Initialized\n");
|
|
return DB_E_ALREADYINITIALIZED;
|
|
}
|
|
delete m_pCUtlPropInfo;
|
|
m_pCUtlPropInfo = NULL;
|
|
ATLTRY(m_pCUtlPropInfo = new CUtlPropInfo<T>())
|
|
if (m_pCUtlPropInfo == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBInitializeImpl::Initialize Error : OOM\n");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
hr = m_pCUtlPropInfo->FInit();
|
|
if (hr == S_OK)
|
|
{
|
|
pT->m_dwStatus |= DSF_INITIALIZED;
|
|
}
|
|
else
|
|
{
|
|
delete m_pCUtlPropInfo;
|
|
m_pCUtlPropInfo = NULL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
// Implementation Class
|
|
|
|
class CPropColID :
|
|
public PROPCOLID,
|
|
public CDBIDOps
|
|
{
|
|
public:
|
|
CPropColID()
|
|
{
|
|
VariantInit(&vValue);
|
|
}
|
|
~CPropColID()
|
|
{
|
|
FreeDBIDs(&dbidProperty);
|
|
VariantClear(&vValue);
|
|
}
|
|
bool operator==(const CPropColID& colId)
|
|
{
|
|
return (CompareDBIDs(&dbidProperty, &(colId.dbidProperty)) == S_OK) ? true : false;
|
|
}
|
|
|
|
};
|
|
|
|
class CColumnIds :
|
|
public CDBIDOps,
|
|
public CSimpleArray<CPropColID>
|
|
|
|
{
|
|
public:
|
|
PPROPCOLID AddNode()
|
|
{
|
|
CPropColID colID;
|
|
if (Add(colID))
|
|
return &(m_aT[GetSize()]);
|
|
return NULL;
|
|
}
|
|
HRESULT RemoveColumnId(const DBID* pdbidProp)
|
|
{
|
|
for (int i = 0; i < GetSize(); i++)
|
|
{
|
|
if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK)
|
|
return (RemoveAt(i)) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
HRESULT AddColumnId(DBPROP* pProp)
|
|
{
|
|
CPropColID colID;
|
|
HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pProp->colid));
|
|
if(FAILED(hr))
|
|
return hr;
|
|
colID.dwOption = pProp->dwOptions;
|
|
hr = VariantCopy(&(colID.vValue),&(pProp->vValue));
|
|
if(FAILED(hr))
|
|
return hr;
|
|
return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
|
|
|
|
}
|
|
HRESULT AddColumnId(PPROPCOLID pPropNode)
|
|
{
|
|
CPropColID colID;
|
|
HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pPropNode->dbidProperty));
|
|
if(FAILED(hr))
|
|
return hr;
|
|
colID.dwOption = pPropNode->dwOption;
|
|
hr = VariantCopy(&(colID.vValue),&(pPropNode->vValue));
|
|
if(FAILED(hr))
|
|
return hr;
|
|
return (Add(colID)) ? S_OK : E_OUTOFMEMORY;
|
|
|
|
}
|
|
ULONG GetCountOfPropColids(){ return (ULONG)GetSize();}
|
|
PPROPCOLID FindColumnId(const DBID* pdbidProp)
|
|
{
|
|
for (int i = 0; i < GetSize(); i++)
|
|
{
|
|
if (CompareDBIDs(pdbidProp, &(m_aT[i].dbidProperty)) == S_OK)
|
|
return &(m_aT[i]);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
HRESULT GetValue(int iColId, DWORD* pdwOptions, DBID* pColid, VARIANT* pvValue)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ATLASSERT(pdwOptions && pColid && pvValue);
|
|
ATLASSERT(iColId >= 0 && iColId < m_nSize);
|
|
|
|
CPropColID& colId = m_aT[iColId];
|
|
*pdwOptions = colId.dwOption;
|
|
CopyDBIDs( pColid, &(colId.dbidProperty) );
|
|
if(FAILED(hr = VariantCopy(pvValue, &(colId.vValue))))
|
|
return hr;
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
const ULONG cchDescBuffSize = 256;
|
|
const DWORD DBINTERNFLAGS_CHANGED = 0x00000001;
|
|
// Rules for GetPropertiesArgChk
|
|
const DWORD ARGCHK_PROPERTIESINERROR = 0x00000001;
|
|
|
|
// Implementation Class
|
|
template <class T>
|
|
class CUtlPropInfo : public CBitFieldOps, public CDBIDOps
|
|
{
|
|
public:
|
|
enum EnumGetPropInfo
|
|
{
|
|
GETPROPINFO_ALLPROPIDS = 0x0001,
|
|
GETPROPINFO_NOTSUPPORTED = 0x0002,
|
|
GETPROPINFO_ERRORSOCCURRED = 0x0004,
|
|
GETPROPINFO_VALIDPROP = 0x0008
|
|
};
|
|
|
|
CUtlPropInfo()
|
|
{
|
|
m_cUPropSet = 0;
|
|
m_pUPropSet = NULL;
|
|
|
|
m_cPropSetDex = 0;
|
|
m_rgiPropSetDex = NULL;
|
|
|
|
m_cElemPerSupported = 0;
|
|
m_rgdwSupported = NULL;
|
|
}
|
|
~CUtlPropInfo()
|
|
{
|
|
delete[] m_rgiPropSetDex;
|
|
delete[] m_rgdwSupported;
|
|
if (m_pUPropSet != NULL)
|
|
CoTaskMemFree(m_pUPropSet);
|
|
}
|
|
|
|
//Determine the number of description buffers needed
|
|
ULONG CalcDescripBuffers(ULONG cPropInfoSet, DBPROPINFOSET* pPropInfoSet)
|
|
{
|
|
ULONG cBuffers = 0;
|
|
|
|
ATLASSERT(m_pUPropSet);
|
|
ATLASSERT(cPropInfoSet && pPropInfoSet);
|
|
|
|
for(ULONG ulSet=0; ulSet<cPropInfoSet; ulSet++)
|
|
{
|
|
if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)
|
|
{
|
|
for(ULONG ul=0; ul<m_cPropSetDex; ul++)
|
|
{
|
|
cBuffers += m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
return cBuffers;
|
|
}
|
|
//Retrieve the property set indexes that match this property set.
|
|
HRESULT GetPropertySetIndex(const GUID* pPropertySet)
|
|
{
|
|
DWORD dwFlag = 0;
|
|
ULONG ulSet;
|
|
|
|
ATLASSERT(m_cUPropSet && m_pUPropSet);
|
|
ATLASSERT(m_rgiPropSetDex);
|
|
ATLASSERT(pPropertySet);
|
|
|
|
m_cPropSetDex = 0;
|
|
|
|
if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEALL))
|
|
{
|
|
dwFlag = DBPROPFLAGS_DATASOURCE;
|
|
}
|
|
else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_DATASOURCEINFOALL))
|
|
{
|
|
dwFlag = DBPROPFLAGS_DATASOURCEINFO;
|
|
}
|
|
else if(InlineIsEqualGUID(*pPropertySet, DBPROPSET_ROWSETALL))
|
|
{
|
|
dwFlag = DBPROPFLAGS_ROWSET;
|
|
}
|
|
else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_DBINITALL))
|
|
{
|
|
dwFlag = DBPROPFLAGS_DBINIT;
|
|
}
|
|
else if(InlineIsEqualGUID(*pPropertySet,DBPROPSET_SESSIONALL))
|
|
{
|
|
dwFlag = DBPROPFLAGS_SESSION;
|
|
}
|
|
else // No scan required, just look for match.
|
|
{
|
|
for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
|
|
{
|
|
if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet )
|
|
{
|
|
m_rgiPropSetDex[m_cPropSetDex] = ulSet;
|
|
m_cPropSetDex++;
|
|
break;
|
|
}
|
|
}
|
|
goto EXIT;
|
|
}
|
|
|
|
// Scan through the property sets looking for matching attributes
|
|
for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
|
|
{
|
|
if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
|
|
{
|
|
m_rgiPropSetDex[m_cPropSetDex] = ulSet;
|
|
m_cPropSetDex++;
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
return (m_cPropSetDex) ? S_OK : S_FALSE;
|
|
|
|
}
|
|
//Retrieve the property id pointer
|
|
HRESULT GetUPropInfoPtr(ULONG iPropSetDex, DBPROPID dwPropertyId, UPROPINFO** ppUPropInfo)
|
|
{
|
|
// Scan through the property sets looking for matching attributes
|
|
for(ULONG ulProps=0; ulProps<m_pUPropSet[iPropSetDex].cUPropInfo; ulProps++)
|
|
{
|
|
if( m_pUPropSet[iPropSetDex].pUPropInfo[ulProps].dwPropId == dwPropertyId )
|
|
{
|
|
*ppUPropInfo = &(m_pUPropSet[iPropSetDex].pUPropInfo[ulProps]);
|
|
// Test to see if the property is supported for this
|
|
// instantiation
|
|
return (TESTBIT(&(m_rgdwSupported[iPropSetDex * m_cElemPerSupported]), ulProps)) ? S_OK : S_FALSE;
|
|
}
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
HRESULT FInit(GUID* pguidSet = (GUID*)&GUID_NULL)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = InitAvailUPropSets(&m_cUPropSet, &m_pUPropSet, &m_cElemPerSupported, pguidSet);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
ATLASSERT((m_cUPropSet != 0) && (m_cElemPerSupported != 0));
|
|
if(!m_cUPropSet || !m_cElemPerSupported)
|
|
return E_FAIL;
|
|
|
|
ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
|
|
if(m_rgdwSupported == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if(FAILED(hr = InitUPropSetsSupported()))
|
|
{
|
|
delete[] m_rgdwSupported;
|
|
m_rgdwSupported = NULL;
|
|
return hr;
|
|
}
|
|
if(m_cUPropSet)
|
|
{
|
|
ATLTRY(m_rgiPropSetDex = new ULONG[m_cUPropSet])
|
|
if(m_rgiPropSetDex == NULL)
|
|
{
|
|
delete [] m_rgdwSupported;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
HRESULT GetPropertyInfo(ULONG cPropertySets,
|
|
const DBPROPIDSET rgPropertySets[], ULONG* pcPropertyInfoSets,
|
|
DBPROPINFOSET** prgPropertyInfoSets,
|
|
WCHAR** ppDescBuffer, bool bInitialized = true,
|
|
const GUID* pGuid = NULL)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG ul, ulSet, ulNext, ulEnd;
|
|
ULONG ulOutIndex;
|
|
ULONG cSets;
|
|
ULONG cPropInfos;
|
|
ULONG ulIndex = 0;
|
|
DWORD dwStatus = 0;
|
|
DBPROPINFO* pPropInfo = NULL;
|
|
DBPROPINFO* pCurPropInfo = NULL;
|
|
WCHAR* pDescBuffer = NULL;
|
|
DBPROPINFOSET* pPropInfoSet = NULL;
|
|
UPROPINFO* pUPropInfo = NULL;
|
|
WCHAR wszBuff[256];
|
|
int cch;
|
|
|
|
// If the consumer does not restrict the property sets
|
|
// by specify an array of property sets and a cPropertySets
|
|
// greater than 0, then we need to make sure we
|
|
// have some to return
|
|
if(cPropertySets == 0)
|
|
{
|
|
// Determine the number of property sets supported
|
|
// In this case, it usually the enumerator or data source asking for
|
|
// DBPROPSET_DBINIT information.
|
|
|
|
if (pGuid != NULL)
|
|
cSets = 1;
|
|
else
|
|
cSets = m_cUPropSet;
|
|
}
|
|
else
|
|
{
|
|
cSets = 0;
|
|
|
|
// Determine number of property sets required
|
|
// This is only required when any of the "special" property set GUIDs were specified
|
|
for(ulSet=0; ulSet<cPropertySets; ulSet++)
|
|
{
|
|
if (GetPropertySetIndex(&(rgPropertySets[ulSet].guidPropertySet)) == S_OK)
|
|
cSets += m_cPropSetDex;
|
|
else
|
|
cSets++;
|
|
}
|
|
}
|
|
ATLASSERT(cSets);
|
|
|
|
// Allocate the DBPROPINFOSET structures
|
|
pPropInfoSet = (DBPROPINFOSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPINFOSET));
|
|
if(pPropInfoSet == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n");
|
|
hr = E_OUTOFMEMORY;
|
|
goto EXIT;
|
|
}
|
|
|
|
memset(pPropInfoSet, 0, cSets * sizeof(DBPROPINFOSET));
|
|
|
|
ulOutIndex = 0;
|
|
// VC 6.0 ulEnd = cPropertySets == 0 ? cSets : cPropertySets;
|
|
ulEnd = cSets; // VC 6.0 SP3
|
|
|
|
// Fill in the output array
|
|
for(ulSet=0; ulSet<ulEnd; ulSet++)
|
|
{
|
|
// Depending of if Property sets are specified store the
|
|
// return property set.
|
|
if (cPropertySets == 0)
|
|
{
|
|
if (pGuid != NULL)
|
|
{
|
|
GUID const& guidSet = *pGuid;
|
|
if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) ||
|
|
InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) ||
|
|
InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) ||
|
|
InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) ||
|
|
InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) &&
|
|
GetPropertySetIndex(&guidSet) == S_OK )
|
|
{
|
|
for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++)
|
|
{
|
|
pPropInfoSet[ulOutIndex].guidPropertySet = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet);
|
|
pPropInfoSet[ulOutIndex].cPropertyInfos = 0;
|
|
ulIndex = m_rgiPropSetDex[ul];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (ULONG l=0; l<m_cUPropSet; l++)
|
|
{
|
|
if (InlineIsEqualGUID(*m_pUPropSet[l].pPropSet, *pGuid))
|
|
ulIndex = l;
|
|
}
|
|
|
|
if (l == m_cUPropSet)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Property Info Set not supported");
|
|
ulIndex = 0;
|
|
}
|
|
pPropInfoSet[ulSet].guidPropertySet = *pGuid;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPropInfoSet[ulSet].guidPropertySet = *(m_pUPropSet[ulSet].pPropSet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GUID const& guidSet = rgPropertySets[ulSet].guidPropertySet;
|
|
if( (InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEALL) ||
|
|
InlineIsEqualGUID(guidSet, DBPROPSET_DATASOURCEINFOALL) ||
|
|
InlineIsEqualGUID(guidSet, DBPROPSET_DBINITALL) ||
|
|
InlineIsEqualGUID(guidSet, DBPROPSET_SESSIONALL) ||
|
|
InlineIsEqualGUID(guidSet, DBPROPSET_ROWSETALL)) &&
|
|
GetPropertySetIndex(&guidSet) == S_OK )
|
|
{
|
|
for(ul=0; ul<m_cPropSetDex; ul++,ulOutIndex++)
|
|
{
|
|
pPropInfoSet[ulOutIndex].guidPropertySet = *(m_pUPropSet[m_rgiPropSetDex[ul]].pPropSet);
|
|
pPropInfoSet[ulOutIndex].cPropertyInfos = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Handle non-category property sets
|
|
// Handle unknown property sets
|
|
pPropInfoSet[ulOutIndex].guidPropertySet = guidSet;
|
|
pPropInfoSet[ulOutIndex].cPropertyInfos = rgPropertySets[ulSet].cPropertyIDs;
|
|
ulOutIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Allocate a Description Buffer if needed
|
|
if( ppDescBuffer )
|
|
{
|
|
ULONG cBuffers = CalcDescripBuffers(cSets, pPropInfoSet);
|
|
if( cBuffers != 0 )
|
|
{
|
|
pDescBuffer = (WCHAR*)CoTaskMemAlloc(cBuffers * cchDescBuffSize * sizeof(WCHAR));
|
|
if(pDescBuffer == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto EXIT;
|
|
}
|
|
*ppDescBuffer = pDescBuffer;
|
|
memset(pDescBuffer, 0, (cBuffers * cchDescBuffSize * sizeof(WCHAR)));
|
|
}
|
|
}
|
|
|
|
// Process requested or derived Property sets
|
|
dwStatus = 0;
|
|
for(ulSet=0; ulSet<cSets; ulSet++)
|
|
{
|
|
ulNext=0;
|
|
cPropInfos = 0;
|
|
pPropInfo = NULL;
|
|
dwStatus &= (GETPROPINFO_ERRORSOCCURRED | GETPROPINFO_VALIDPROP);
|
|
|
|
// Calculate the number of property nodes needed for this
|
|
// property set.
|
|
if( cPropertySets == 0 )
|
|
{
|
|
ULONG ulTempSet;
|
|
if (pGuid != NULL)
|
|
ulTempSet = ulIndex;
|
|
else
|
|
ulTempSet = ulSet;
|
|
|
|
cPropInfos = m_pUPropSet[ulTempSet].cUPropInfo;
|
|
dwStatus |= GETPROPINFO_ALLPROPIDS;
|
|
m_rgiPropSetDex[0] = ulTempSet;
|
|
m_cPropSetDex = 1;
|
|
}
|
|
else
|
|
{
|
|
// If the count of PROPIDs is 0 (NOTE: the above routine already determined
|
|
// if it belonged to a category and if so set the count of properties to 0 for
|
|
// each propset in that category.
|
|
if( pPropInfoSet[ulSet].cPropertyInfos == 0 )
|
|
{
|
|
dwStatus |= GETPROPINFO_ALLPROPIDS;
|
|
// We have to determine if the property set is supported and if so
|
|
// the count of properties in the set.
|
|
if( GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_OK)
|
|
{
|
|
ATLASSERT( m_cPropSetDex == 1 );
|
|
|
|
cPropInfos += m_pUPropSet[m_rgiPropSetDex[0]].cUPropInfo;
|
|
}
|
|
else
|
|
{
|
|
// Not Supported
|
|
dwStatus |= GETPROPINFO_ERRORSOCCURRED;
|
|
goto NEXT_SET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We also handle the case here where the user has requested
|
|
// a non-initialization group property info set while the
|
|
// provider is not initialized. In this case, properties should
|
|
// not be set.
|
|
cPropInfos = pPropInfoSet[ulSet].cPropertyInfos;
|
|
if( (GetPropertySetIndex(&(pPropInfoSet[ulSet].guidPropertySet)) == S_FALSE)
|
|
|| (!bInitialized &&
|
|
!(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINIT)) &&
|
|
!(InlineIsEqualGUID(pPropInfoSet[ulSet].guidPropertySet, DBPROPSET_DBINITALL))))
|
|
{
|
|
dwStatus |= GETPROPINFO_NOTSUPPORTED;
|
|
dwStatus |= GETPROPINFO_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Allocate DBPROP array
|
|
ATLASSERT( cPropInfos != 0 );
|
|
pPropInfo = (DBPROPINFO*)CoTaskMemAlloc(cPropInfos * sizeof(DBPROPINFO));
|
|
if( pPropInfo )
|
|
{
|
|
// Initialize Buffer
|
|
memset(pPropInfo, 0, cPropInfos * sizeof(DBPROPINFO));
|
|
for(ULONG ulProp=0; ulProp<cPropInfos; ulProp++)
|
|
{
|
|
VariantInit(&(pPropInfo[ulProp].vValues));
|
|
if( dwStatus & GETPROPINFO_NOTSUPPORTED )
|
|
{
|
|
// Not supported, thus we need to mark all as NOT_SUPPORTED
|
|
pPropInfo[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
|
|
pPropInfo[ulProp].dwFlags = DBPROPFLAGS_NOTSUPPORTED;
|
|
dwStatus |= GETPROPINFO_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
// Make sure we support the property set
|
|
if( dwStatus & GETPROPINFO_NOTSUPPORTED )
|
|
{
|
|
ulNext = cPropInfos;
|
|
goto NEXT_SET;
|
|
}
|
|
|
|
// Retrieve the property information for this property set
|
|
for(ul=0; ul<m_cPropSetDex; ul++)
|
|
{
|
|
pUPropInfo = (m_pUPropSet[m_rgiPropSetDex[ul]].pUPropInfo);
|
|
ATLASSERT( pUPropInfo );
|
|
|
|
// Retrieve current value of properties
|
|
if( dwStatus & GETPROPINFO_ALLPROPIDS )
|
|
{
|
|
for(ulProp=0; ulProp<m_pUPropSet[m_rgiPropSetDex[ul]].cUPropInfo; ulProp++)
|
|
{
|
|
// Verify property is supported, if not do not return
|
|
if( !TESTBIT(&(m_rgdwSupported[m_rgiPropSetDex[ul] * m_cElemPerSupported]), ulProp) )
|
|
continue;
|
|
|
|
pCurPropInfo = &(pPropInfo[ulNext]);
|
|
|
|
// If the ppDescBuffer pointer was not NULL, then
|
|
// we need supply description of the properties
|
|
if( ppDescBuffer )
|
|
{
|
|
// Set Buffer pointer
|
|
pCurPropInfo->pwszDescription = pDescBuffer;
|
|
|
|
// Load the string into temp buffer
|
|
cch = LoadDescription(pUPropInfo[ulProp].ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff)));
|
|
if( cch )
|
|
{
|
|
// Adjust for '\0'
|
|
cch++;
|
|
|
|
// Transfer to official buffer if room
|
|
memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR));
|
|
pDescBuffer += cch;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pDescBuffer, L"UNKNOWN");
|
|
pDescBuffer += (wcslen(L"UNKNOWN") + 1);
|
|
}
|
|
}
|
|
|
|
pCurPropInfo->dwPropertyID = pUPropInfo[ulProp].dwPropId;
|
|
pCurPropInfo->dwFlags = pUPropInfo[ulProp].dwFlags;
|
|
pCurPropInfo->vtType = pUPropInfo[ulProp].VarType;
|
|
pCurPropInfo->vValues.vt = VT_EMPTY;
|
|
|
|
dwStatus |= GETPROPINFO_VALIDPROP;
|
|
// Increment to next available buffer
|
|
ulNext++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( m_cPropSetDex == 1 );
|
|
|
|
for( ulProp = 0; ulProp < cPropInfos; ulProp++, ulNext++ )
|
|
{
|
|
pCurPropInfo = &(pPropInfo[ulNext]);
|
|
|
|
// Process Properties based on Restriction array.
|
|
pCurPropInfo->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
|
|
|
|
if( GetUPropInfoPtr(m_rgiPropSetDex[ul], pCurPropInfo->dwPropertyID, &pUPropInfo)
|
|
== S_OK )
|
|
{
|
|
// If the ppDescBuffer pointer was not NULL, then
|
|
// we need supply description of the properties
|
|
if( ppDescBuffer )
|
|
{
|
|
// Set Buffer pointer
|
|
pCurPropInfo->pwszDescription = pDescBuffer;
|
|
|
|
// Load the string into temp buffer
|
|
cch = LoadDescription(pUPropInfo->ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff)));
|
|
if( cch )
|
|
{
|
|
// Adjust for '\0'
|
|
cch++;
|
|
|
|
// Transfer to official buffer if room
|
|
memcpy(pDescBuffer, wszBuff, cch * sizeof(WCHAR));
|
|
pDescBuffer += cch;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pDescBuffer, L"UNKNOWN");
|
|
pDescBuffer += (wcslen(L"UNKNOWN") + 1);
|
|
}
|
|
}
|
|
|
|
pCurPropInfo->dwPropertyID = pUPropInfo->dwPropId;
|
|
pCurPropInfo->dwFlags = pUPropInfo->dwFlags;
|
|
pCurPropInfo->vtType = pUPropInfo->VarType;
|
|
|
|
dwStatus |= GETPROPINFO_VALIDPROP;
|
|
}
|
|
else
|
|
{
|
|
// Not Supported
|
|
pCurPropInfo->dwFlags = DBPROPFLAGS_NOTSUPPORTED;
|
|
dwStatus |= GETPROPINFO_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto EXIT;
|
|
}
|
|
|
|
NEXT_SET:
|
|
pPropInfoSet[ulSet].cPropertyInfos = ulNext;
|
|
pPropInfoSet[ulSet].rgPropertyInfos = pPropInfo;
|
|
}
|
|
|
|
// Success, set return values
|
|
*pcPropertyInfoSets = cSets;
|
|
*prgPropertyInfoSets = pPropInfoSet;
|
|
|
|
// At least one propid was marked as not S_OK
|
|
if( dwStatus & GETPROPINFO_ERRORSOCCURRED )
|
|
{
|
|
// If at least 1 property was set
|
|
if( dwStatus & GETPROPINFO_VALIDPROP )
|
|
return DB_S_ERRORSOCCURRED;
|
|
else
|
|
{
|
|
// Do not free any of the rgPropertyInfoSets, but
|
|
// do free the ppDescBuffer
|
|
if( pDescBuffer )
|
|
{
|
|
ATLASSERT( ppDescBuffer );
|
|
CoTaskMemFree(pDescBuffer);
|
|
*ppDescBuffer = NULL;
|
|
}
|
|
return DB_E_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
EXIT:
|
|
// Check if failure and clean up any allocated memory
|
|
if( FAILED(hr) &&
|
|
(hr != DB_E_ERRORSOCCURRED) )
|
|
{
|
|
// Free Description Buffer
|
|
if( pDescBuffer )
|
|
{
|
|
ATLASSERT( ppDescBuffer );
|
|
|
|
CoTaskMemFree(pDescBuffer);
|
|
*ppDescBuffer = NULL;
|
|
}
|
|
|
|
if( pPropInfoSet )
|
|
{
|
|
// Loop through Property Sets
|
|
for(ulSet=0; ulSet<cSets; ulSet++)
|
|
{
|
|
if( pPropInfoSet[ulSet].rgPropertyInfos )
|
|
CoTaskMemFree(pPropInfoSet[ulSet].rgPropertyInfos);
|
|
}
|
|
|
|
CoTaskMemFree(pPropInfoSet);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
ULONG m_cUPropSet; //count of UPropSet items
|
|
UPROPSET* m_pUPropSet; //Pointer to UPropset items
|
|
ULONG m_cPropSetDex; //count of UPropSet Indexes
|
|
ULONG* m_rgiPropSetDex;//array of UPropSet Index values
|
|
ULONG m_cElemPerSupported; //number of DWORDS per UPropSet to indicate supported UPropIds
|
|
DWORD* m_rgdwSupported;//array of DWORDs indicating supported UPropIds
|
|
|
|
HRESULT InitAvailUPropSets(ULONG* pcUPropSet, UPROPSET** ppUPropSet, ULONG* pcElemPerSupported, GUID* pguid)
|
|
{
|
|
ATLASSERT(pcUPropSet && ppUPropSet);
|
|
if (*ppUPropSet != NULL)
|
|
{
|
|
CoTaskMemFree(*ppUPropSet);
|
|
*ppUPropSet = NULL;
|
|
}
|
|
int cSets = (int)(INT_PTR)T::_GetPropSet(NULL, pcElemPerSupported);
|
|
UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
|
|
if (pSet == NULL)
|
|
return E_OUTOFMEMORY;
|
|
*ppUPropSet = T::_GetPropSet(pcUPropSet, pcElemPerSupported, pSet, pguid);
|
|
return S_OK;
|
|
}
|
|
virtual HRESULT InitUPropSetsSupported()
|
|
{
|
|
ULONG cPropSet = 0, cElemsPerSupported = 0;
|
|
int cSets = (int)(INT_PTR)T::_GetPropSet(NULL, &cElemsPerSupported);
|
|
UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
|
|
if (pSet == NULL)
|
|
return E_OUTOFMEMORY;
|
|
pSet = T::_GetPropSet(&cPropSet, &cElemsPerSupported, pSet);
|
|
memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD));
|
|
CoTaskMemFree(pSet);
|
|
return S_OK;
|
|
}
|
|
//Load a localized description
|
|
int LoadDescription(ULONG ids, PWSTR pwszBuff, ULONG cchBuff)
|
|
{
|
|
USES_CONVERSION;
|
|
TCHAR* pszBuf = (TCHAR*)_alloca(cchBuff * sizeof(TCHAR));
|
|
if (pszBuf == NULL)
|
|
return 0;
|
|
int nTemp = LoadString(_pModule->GetResourceInstance(), ids, pszBuf, cchBuff);
|
|
wcscpy(pwszBuff, T2W(pszBuf));
|
|
return nTemp;
|
|
}
|
|
};
|
|
|
|
class ATL_NO_VTABLE CUtlPropsBase : public CBitFieldOps, public CDBIDOps
|
|
{
|
|
public:
|
|
|
|
ULONG m_cUPropSet; //count of UPropSet items
|
|
UPROPSET* m_pUPropSet; //Pointer to UPropset items
|
|
UPROP* m_pUProp;
|
|
ULONG m_cUPropSetHidden; //Count of Hidden items
|
|
DWORD m_dwFlags; //Configuration flags
|
|
ULONG m_cPropSetDex; //count of UPropSet Indexes
|
|
ULONG* m_rgiPropSetDex; //pointer to Array of UPropSet Index values
|
|
ULONG m_cElemPerSupported;//number of DWORDS per UPropSet to indicate supported UPropIds
|
|
DWORD* m_rgdwSupported; //pointer to array of DWORDs indicating supported UPropIds
|
|
DWORD* m_rgdwPropsInError;//pointer to array of DWORDs indicating if property is in error
|
|
|
|
enum EnumUPropSetFlags
|
|
{
|
|
UPROPSET_HIDDEN = 0x00000001,
|
|
UPROPSET_PASSTHROUGH = 0x00000002
|
|
};
|
|
enum EnumGetProp
|
|
{
|
|
GETPROP_ALLPROPIDS = 0x0001,
|
|
GETPROP_NOTSUPPORTED = 0x0002,
|
|
GETPROP_ERRORSOCCURRED = 0x0004,
|
|
GETPROP_VALIDPROP = 0x0008,
|
|
GETPROP_PROPSINERROR = 0x0010
|
|
};
|
|
|
|
enum EnumSetProp
|
|
{
|
|
SETPROP_BADOPTION = 0x0001,
|
|
SETPROP_NOTSUPPORTED = 0x0002,
|
|
SETPROP_VALIDPROP = 0x0004,
|
|
SETPROP_ERRORS = 0x0008,
|
|
SETPROP_COLUMN_LEVEL = 0x0010,
|
|
SETPROP_WAS_REQUIRED = 0x0020
|
|
};
|
|
|
|
HRESULT SetPassThrough(const DBPROPSET* pPropSet)
|
|
{
|
|
ATLASSERT(pPropSet);
|
|
|
|
DBPROP* pProp = pPropSet->rgProperties;
|
|
|
|
//Default implementation just sets all properties as NOTSUPPORTED
|
|
for( ULONG ul=0; ul<pPropSet->cProperties; ul++, pProp++ )
|
|
pProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
|
|
|
|
return DB_E_ERRORSOCCURRED;
|
|
}
|
|
|
|
HRESULT GetIndexofPropIdinPropSet(ULONG iCurSet, DBPROPID dwPropertyId, ULONG* piCurPropId)
|
|
{
|
|
ATLASSERT(piCurPropId);
|
|
UPROPINFO* pUPropInfo = m_pUPropSet[iCurSet].pUPropInfo;
|
|
for(ULONG ul=0; ul<m_pUPropSet[iCurSet].cUPropInfo; ul++)
|
|
{
|
|
if( dwPropertyId == pUPropInfo[ul].dwPropId )
|
|
{
|
|
*piCurPropId = ul;
|
|
// Test to see if the property is supported for this
|
|
// instantiation
|
|
return (TESTBIT(&(m_rgdwSupported[iCurSet * m_cElemPerSupported]), ul)) ? S_OK : S_FALSE;
|
|
}
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
virtual HRESULT IsValidValue(ULONG /*iCurSet*/, DBPROP* pDBProp)
|
|
{
|
|
ATLASSERT(pDBProp != NULL);
|
|
CComVariant var = pDBProp->vValue;
|
|
if (var.vt == VT_BOOL)
|
|
{
|
|
if (var.boolVal != VARIANT_TRUE && var.boolVal != VARIANT_FALSE)
|
|
return S_FALSE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/) = 0;
|
|
|
|
HRESULT SetProperty(ULONG iCurSet, ULONG iCurProp, DBPROP* pDBProp)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
UPROP* pUProp;
|
|
UPROPVAL* pUPropVal;
|
|
UPROPINFO* pUPropInfo;
|
|
ULONG iUProp;
|
|
|
|
ATLASSERT( pDBProp );
|
|
|
|
// Set pointer to correct set
|
|
pUProp = &(m_pUProp[iCurSet]);
|
|
ATLASSERT( pUProp );
|
|
|
|
pUPropInfo = &(m_pUPropSet[iCurSet].pUPropInfo[iCurProp]);
|
|
ATLASSERT( pUPropInfo );
|
|
|
|
// Determine the index within m_pUProp
|
|
for(iUProp=0; iUProp<pUProp->cPropIds; iUProp++)
|
|
{
|
|
if( (pUProp->rgpUPropInfo[iUProp])->dwPropId == pDBProp->dwPropertyID )
|
|
break;
|
|
}
|
|
|
|
if( iUProp >= pUProp->cPropIds )
|
|
{
|
|
ATLASSERT( !"Should have found index of property to set" );
|
|
hr = E_FAIL;
|
|
pDBProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
|
|
goto EXIT;
|
|
}
|
|
|
|
//Get the UPROPVAL node pointer within that propset.
|
|
pUPropVal = &(pUProp->pUPropVal[iUProp]);
|
|
ATLASSERT( pUPropVal );
|
|
|
|
// Handle VT_EMPTY, which indicates to the provider to
|
|
// reset this property to the providers default
|
|
if( pDBProp->vValue.vt == VT_EMPTY )
|
|
{
|
|
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
|
|
{
|
|
// Remove any nodes, because the default applies to
|
|
// all columns
|
|
delete pUPropVal->pCColumnIds;
|
|
pUPropVal->pCColumnIds = NULL;
|
|
}
|
|
|
|
// Should clear here, since previous values may already
|
|
// have been cached and need to be replaced.
|
|
VariantClear(&(pUPropVal->vValue));
|
|
|
|
pUPropVal->dwFlags &= ~DBINTERNFLAGS_CHANGED;
|
|
hr = GetDefaultValue(iCurSet, pDBProp->dwPropertyID,
|
|
&(pUPropVal->dwOption), &(pUPropVal->vValue));
|
|
|
|
goto EXIT;
|
|
}
|
|
|
|
|
|
// Column Level
|
|
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
|
|
{
|
|
// Check to see if it applies to all
|
|
if( (CompareDBIDs(&(pDBProp->colid), &DB_NULLID) == S_OK) )
|
|
{
|
|
// Remove the Columns Storage object
|
|
delete pUPropVal->pCColumnIds;
|
|
pUPropVal->pCColumnIds = NULL;
|
|
pUPropVal->dwOption = pDBProp->dwOptions;
|
|
if( FAILED(hr = VariantCopy(&(pUPropVal->vValue),
|
|
&(pDBProp->vValue))) )
|
|
goto EXIT;
|
|
pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
|
|
}
|
|
else // Does not apply to all columns
|
|
{
|
|
if( pUPropVal->pCColumnIds == NULL )
|
|
ATLTRY(pUPropVal->pCColumnIds = new CColumnIds)
|
|
|
|
if( pUPropVal->pCColumnIds )
|
|
{
|
|
if( FAILED(hr = (pUPropVal->pCColumnIds)->AddColumnId(pDBProp)) )
|
|
goto EXIT;
|
|
pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto EXIT;
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Set for non-column level properties
|
|
pUPropVal->dwOption = pDBProp->dwOptions;
|
|
if( FAILED(hr = VariantCopy(&(pUPropVal->vValue),
|
|
&(pDBProp->vValue))) )
|
|
goto EXIT;
|
|
OnPropertyChanged(iCurSet, pDBProp);
|
|
pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED;
|
|
}
|
|
|
|
EXIT:
|
|
if( SUCCEEDED(hr) )
|
|
pDBProp->dwStatus = DBPROPSTATUS_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SetProperties(const DWORD /*dwStatus*/, const ULONG cPropertySets,
|
|
const DBPROPSET rgPropertySets[], const ULONG cSelectProps = 1,
|
|
const GUID** ppGuid = NULL, bool bIsCreating = false)
|
|
{
|
|
DWORD dwState = 0;
|
|
ULONG ulCurSet, ulProp, ulCurProp = 0;
|
|
DBPROP* rgDBProp;
|
|
UPROPINFO* pUPropInfo;
|
|
VARIANT vDefaultValue;
|
|
DWORD dwOption;
|
|
|
|
// ppGuid specifies the property sets that the consumer can set based
|
|
// on the interface that called this function.
|
|
ATLASSERT(ppGuid != NULL);
|
|
|
|
if ((cPropertySets != 0) && (rgPropertySets == NULL))
|
|
return E_INVALIDARG;
|
|
|
|
// Initialize Variant
|
|
VariantInit(&vDefaultValue);
|
|
|
|
// Process property sets
|
|
for(ULONG ulSet=0; ulSet<cPropertySets; ulSet++)
|
|
{
|
|
if ((rgPropertySets[ulSet].cProperties != 0) && (rgPropertySets[ulSet].rgProperties == NULL))
|
|
return E_INVALIDARG;
|
|
|
|
bool bAvailable = false;
|
|
for (ULONG l=0; l<cSelectProps; l++)
|
|
{
|
|
if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
|
|
bAvailable |= true;
|
|
}
|
|
|
|
// Make sure we support the property set
|
|
if( !bAvailable ||
|
|
(GetIndexofPropSet(&(rgPropertySets[ulSet].guidPropertySet), &ulCurSet) == S_FALSE ))
|
|
{
|
|
// Not supported, thus we need to mark all as NOT_SUPPORTED
|
|
rgDBProp = rgPropertySets[ulSet].rgProperties;
|
|
for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
|
|
{
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
|
|
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Handle property sets marked as pass through
|
|
if( m_pUPropSet[ulCurSet].dwFlags & UPROPSET_PASSTHROUGH )
|
|
{
|
|
HRESULT hr = SetPassThrough(&rgPropertySets[ulSet]);
|
|
if( hr == DB_E_ERRORSOCCURRED )
|
|
{
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= SETPROP_WAS_REQUIRED;
|
|
}
|
|
else if( hr == DB_S_ERRORSOCCURRED )
|
|
{
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= SETPROP_VALIDPROP;
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT( hr == S_OK );
|
|
dwState |= SETPROP_VALIDPROP;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Handle properties of a supported property set
|
|
rgDBProp = rgPropertySets[ulSet].rgProperties;
|
|
for(ulProp=0; ulProp<rgPropertySets[ulSet].cProperties; ulProp++)
|
|
{
|
|
// Is this a supported PROPID for this property set
|
|
if( GetIndexofPropIdinPropSet(ulCurSet, rgDBProp[ulProp].dwPropertyID,
|
|
&ulCurProp) == S_FALSE)
|
|
{
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
|
|
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
|
|
continue;
|
|
}
|
|
|
|
// Set the pUPropInfo pointer
|
|
pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
|
|
ATLASSERT( pUPropInfo );
|
|
|
|
// check dwOption for a valid option
|
|
if( (rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_REQUIRED) &&
|
|
(rgDBProp[ulProp].dwOptions != DBPROPOPTIONS_SETIFCHEAP) )
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "SetProperties dwOptions Invalid: %u\n", rgDBProp[ulProp].dwOptions);
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= SETPROP_WAS_REQUIRED;
|
|
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADOPTION;
|
|
continue;
|
|
}
|
|
|
|
// Check that the property is settable
|
|
// We do not check against DBPROPFLAGS_CHANGE here
|
|
if( (pUPropInfo->dwFlags & DBPROPFLAGS_WRITE) == 0 )
|
|
{
|
|
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_OK;
|
|
|
|
VariantClear(&vDefaultValue);
|
|
|
|
// VT_EMPTY against a read only property should be a no-op since
|
|
// the VT_EMPTY means the default.
|
|
if( V_VT(&rgDBProp[ulProp].vValue) == VT_EMPTY )
|
|
{
|
|
dwState |= SETPROP_VALIDPROP;
|
|
continue;
|
|
}
|
|
|
|
if( SUCCEEDED(GetDefaultValue(ulCurSet, rgDBProp[ulProp].dwPropertyID,
|
|
&dwOption, &(vDefaultValue))) )
|
|
{
|
|
if( V_VT(&rgDBProp[ulProp].vValue) == V_VT(&vDefaultValue) )
|
|
{
|
|
switch( V_VT(&vDefaultValue) )
|
|
{
|
|
case VT_BOOL:
|
|
if( V_BOOL(&rgDBProp[ulProp].vValue) == V_BOOL(&vDefaultValue) )
|
|
{
|
|
dwState |= SETPROP_VALIDPROP;
|
|
continue;
|
|
}
|
|
break;
|
|
case VT_I2:
|
|
if( V_I2(&rgDBProp[ulProp].vValue) == V_I2(&vDefaultValue) )
|
|
{
|
|
dwState |= SETPROP_VALIDPROP;
|
|
continue;
|
|
}
|
|
break;
|
|
case VT_I4:
|
|
if( V_I4(&rgDBProp[ulProp].vValue) == V_I4(&vDefaultValue) )
|
|
{
|
|
dwState |= SETPROP_VALIDPROP;
|
|
continue;
|
|
}
|
|
break;
|
|
case VT_BSTR:
|
|
if( wcscmp(V_BSTR(&rgDBProp[ulProp].vValue), V_BSTR(&vDefaultValue)) == 0 )
|
|
{
|
|
dwState |= SETPROP_VALIDPROP;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
|
|
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
|
|
continue;
|
|
}
|
|
|
|
// Check that the property is being set with the correct VARTYPE
|
|
if( (rgDBProp[ulProp].vValue.vt != pUPropInfo->VarType) &&
|
|
(rgDBProp[ulProp].vValue.vt != VT_EMPTY) )
|
|
{
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
|
|
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
|
|
continue;
|
|
}
|
|
|
|
// Check that the value is legal
|
|
if( (rgDBProp[ulProp].vValue.vt != VT_EMPTY) &&
|
|
IsValidValue(ulCurSet, &(rgDBProp[ulProp])) == S_FALSE )
|
|
{
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
|
|
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE;
|
|
continue;
|
|
}
|
|
|
|
|
|
// Check for a bad COLID, we only catch bad DBIDs
|
|
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
|
|
{
|
|
if( CDBIDOps::IsValidDBID(&(rgDBProp[ulProp].colid)) == S_FALSE )
|
|
{
|
|
dwState |= SETPROP_ERRORS;
|
|
dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0;
|
|
rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADCOLUMN;
|
|
continue;
|
|
}
|
|
dwState |= SETPROP_COLUMN_LEVEL;
|
|
|
|
}
|
|
|
|
if( SUCCEEDED(SetProperty(ulCurSet, ulCurProp, /*pUPropInfo,*/ &(rgDBProp[ulProp]))) )
|
|
{
|
|
dwState |= SETPROP_VALIDPROP;
|
|
}
|
|
}
|
|
}
|
|
|
|
VariantClear(&vDefaultValue);
|
|
|
|
// At least one propid was marked as not S_OK
|
|
if( dwState & SETPROP_ERRORS )
|
|
{
|
|
if (!bIsCreating)
|
|
{
|
|
return (dwState & SETPROP_VALIDPROP) ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED;
|
|
}
|
|
else
|
|
{
|
|
return (dwState & SETPROP_WAS_REQUIRED) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
OUT_OF_LINE HRESULT CopyUPropVal(ULONG iPropSet, UPROPVAL* rgUPropVal)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
UPROP* pUProp;
|
|
UPROPVAL* pUPropVal;
|
|
DBPROP dbProp;
|
|
|
|
ATLASSERT(rgUPropVal);
|
|
ATLASSERT(iPropSet < m_cUPropSet);
|
|
|
|
VariantInit(&dbProp.vValue);
|
|
|
|
pUProp = &(m_pUProp[iPropSet]);
|
|
for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
|
|
{
|
|
pUPropVal = &(pUProp->pUPropVal[ul]);
|
|
|
|
// Transfer dwOptions
|
|
rgUPropVal[ul].dwOption = pUPropVal->dwOption;
|
|
|
|
// Transfer Flags
|
|
rgUPropVal[ul].dwFlags = pUPropVal->dwFlags;
|
|
|
|
// Transfer Column Properties
|
|
if( pUPropVal->pCColumnIds )
|
|
{
|
|
ATLTRY(rgUPropVal[ul].pCColumnIds = new CColumnIds)
|
|
if( rgUPropVal[ul].pCColumnIds )
|
|
{
|
|
CColumnIds* pColIds = pUPropVal->pCColumnIds;
|
|
for (int i = 0; i < pColIds->GetSize(); i++)
|
|
{
|
|
hr = (pUPropVal->pCColumnIds)->GetValue(i, &(dbProp.dwOptions),&(dbProp.colid), &(dbProp.vValue));
|
|
if( FAILED(hr) )
|
|
goto EXIT;
|
|
if( FAILED(hr = (rgUPropVal[ul].pCColumnIds)->AddColumnId(&dbProp)) )
|
|
goto EXIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto EXIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rgUPropVal[ul].pCColumnIds = NULL;
|
|
}
|
|
|
|
// Transfer value
|
|
VariantInit(&(rgUPropVal[ul].vValue));
|
|
if( FAILED(hr = VariantCopy(&(rgUPropVal[ul].vValue),
|
|
&(pUPropVal->vValue))) )
|
|
goto EXIT;
|
|
}
|
|
|
|
EXIT:
|
|
VariantClear(&(dbProp.vValue));
|
|
return hr;
|
|
}
|
|
void ClearPropertyInError()
|
|
{
|
|
ATLASSERT( m_rgdwPropsInError );
|
|
memset(m_rgdwPropsInError, 0, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
|
|
}
|
|
|
|
void CopyUPropSetsSupported(DWORD* rgdwSupported)
|
|
{
|
|
memcpy(rgdwSupported, m_rgdwSupported, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
|
|
}
|
|
|
|
virtual HRESULT InitUPropSetsSupported() = 0;
|
|
|
|
virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet) = 0;
|
|
|
|
ULONG GetCountofWritablePropsInPropSet(ULONG iPropSet)
|
|
{
|
|
ULONG cWritable = 0;
|
|
UPROPINFO* pUPropInfo;
|
|
|
|
ATLASSERT( m_pUPropSet );
|
|
ATLASSERT( iPropSet < m_cUPropSet );
|
|
|
|
pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
|
|
|
|
for(ULONG ul=0; ul<m_pUPropSet[iPropSet].cUPropInfo; ul++)
|
|
{
|
|
if( pUPropInfo[ul].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
|
|
cWritable++;
|
|
}
|
|
|
|
return cWritable;
|
|
}
|
|
|
|
void CopyUPropInfo(ULONG iPropSet, UPROPINFO** rgpUPropInfo)
|
|
{
|
|
ATLASSERT( rgpUPropInfo );
|
|
ATLASSERT( iPropSet < m_cUPropSet );
|
|
memcpy(rgpUPropInfo, m_pUProp[iPropSet].rgpUPropInfo, m_pUProp[iPropSet].cPropIds * sizeof(UPROPINFO*));
|
|
}
|
|
|
|
virtual HRESULT GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar) = 0;
|
|
|
|
typedef UPROPSET* (*PGetPropSet)(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet, GUID* pguidSet);
|
|
|
|
HRESULT InternalInitUPropSetsSupported(PGetPropSet pfnGetSet)
|
|
{
|
|
ULONG cPropSet = 0, cElemsPerSupported = 0;
|
|
INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &cElemsPerSupported, NULL, (GUID*)&GUID_NULL);
|
|
UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
|
|
if (pPropSet == NULL)
|
|
return E_OUTOFMEMORY;
|
|
pPropSet = (*pfnGetSet)(&cPropSet, &cElemsPerSupported, pPropSet, (GUID*)&GUID_NULL);
|
|
memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD));
|
|
CoTaskMemFree(pPropSet);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT InternalGetDefaultValue(PGetPropSet pfnGetSet, ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar)
|
|
{
|
|
if (pdwOption == NULL || pVar == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
ULONG cUPropSet = 0, cElemPerSupported =0;
|
|
|
|
INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &cElemPerSupported, NULL, (GUID*)&GUID_NULL);
|
|
UPROPSET* pPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
|
|
if (pPropSet == NULL)
|
|
return E_OUTOFMEMORY;
|
|
pPropSet = (*pfnGetSet)(&cUPropSet, &cElemPerSupported, pPropSet, (GUID*)&GUID_NULL);
|
|
|
|
ATLASSERT(iPropSet < cUPropSet);
|
|
for (ULONG iProp = 0; iProp < pPropSet[iPropSet].cUPropInfo; iProp++)
|
|
{
|
|
UPROPINFO& rInfo = pPropSet[iPropSet].pUPropInfo[iProp];
|
|
if (rInfo.dwPropId == dwPropId)
|
|
{
|
|
pVar->vt = rInfo.VarType;
|
|
*pdwOption = rInfo.dwOption;
|
|
switch(rInfo.VarType)
|
|
{
|
|
case VT_BSTR:
|
|
pVar->bstrVal = SysAllocString(rInfo.szVal);
|
|
break;
|
|
default:
|
|
pVar->lVal = (DWORD)rInfo.dwVal;
|
|
break;
|
|
}
|
|
CoTaskMemFree(pPropSet);
|
|
return S_OK;
|
|
}
|
|
}
|
|
CoTaskMemFree(pPropSet);
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT InternalFInit(PGetPropSet pfnGetSet, CUtlPropsBase* pCopyMe = NULL)
|
|
{
|
|
HRESULT hr;
|
|
ULONG ulPropId;
|
|
ULONG cPropIds;
|
|
ULONG iPropSet;
|
|
ULONG iNewDex;
|
|
UPROPINFO** rgpUPropInfo;
|
|
UPROPVAL* rgUPropVal;
|
|
UPROPINFO* pUPropInfo;
|
|
|
|
// If a pointer is passed in, we should copy that property object
|
|
if( pCopyMe )
|
|
{
|
|
// Establish some base values
|
|
m_cUPropSet = pCopyMe->m_cUPropSet;
|
|
if (m_pUPropSet != NULL)
|
|
CoTaskMemFree(m_pUPropSet);
|
|
m_pUPropSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * m_cUPropSet);
|
|
if (m_pUPropSet == NULL)
|
|
return E_OUTOFMEMORY;
|
|
memcpy(m_pUPropSet, pCopyMe->m_pUPropSet, sizeof(UPROPSET) * m_cUPropSet);
|
|
m_cElemPerSupported = pCopyMe->m_cElemPerSupported;
|
|
ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) );
|
|
// Retrieve Supported Bitmask
|
|
ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
|
|
ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported])
|
|
if( m_rgdwSupported == NULL|| m_rgdwPropsInError == NULL)
|
|
{
|
|
delete[] m_rgdwSupported;
|
|
delete[] m_rgdwPropsInError;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
ClearPropertyInError();
|
|
pCopyMe->CopyUPropSetsSupported(m_rgdwSupported);
|
|
|
|
}
|
|
else
|
|
{
|
|
INT_PTR cSets = (INT_PTR)(*pfnGetSet)(NULL, &m_cElemPerSupported, NULL, (GUID*)&GUID_NULL);
|
|
UPROPSET* pSet = (UPROPSET*)CoTaskMemAlloc(sizeof(UPROPSET) * cSets);
|
|
if (pSet == NULL)
|
|
return E_OUTOFMEMORY;
|
|
pSet = (*pfnGetSet)(&m_cUPropSet, &m_cElemPerSupported, pSet, (GUID*)&GUID_NULL);
|
|
if (m_pUPropSet != NULL)
|
|
CoTaskMemFree(m_pUPropSet);
|
|
m_pUPropSet = pSet;
|
|
ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) );
|
|
if( !m_cUPropSet || !m_cElemPerSupported )
|
|
return E_FAIL;
|
|
|
|
ATLTRY(m_rgdwSupported = new DWORD[m_cUPropSet * m_cElemPerSupported])
|
|
ATLTRY(m_rgdwPropsInError = new DWORD[m_cUPropSet * m_cElemPerSupported])
|
|
if( m_rgdwSupported == NULL || m_rgdwPropsInError == NULL)
|
|
{
|
|
delete[] m_rgdwSupported;
|
|
delete[] m_rgdwPropsInError;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
ClearPropertyInError();
|
|
|
|
if( FAILED(hr = InitUPropSetsSupported()) )
|
|
{
|
|
delete[] m_rgdwSupported;
|
|
m_rgdwSupported = NULL;
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
// Allocate UPROPS structures for the count of Property sets
|
|
ATLTRY(m_pUProp = (UPROP*) new UPROP[m_cUPropSet])
|
|
if( m_pUProp)
|
|
{
|
|
memset(m_pUProp, 0, m_cUPropSet * sizeof(UPROP));
|
|
}
|
|
else
|
|
{
|
|
m_cUPropSet = 0;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// With in the UPROPS Structure allocate and intialize the
|
|
// Property IDs that belong to this property set.
|
|
for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++)
|
|
{
|
|
cPropIds = GetCountofWritablePropsInPropSet(iPropSet);
|
|
|
|
if( cPropIds > 0 )
|
|
{
|
|
ATLTRY(rgpUPropInfo = (UPROPINFO**) new UPROPINFO*[cPropIds])
|
|
ATLTRY(rgUPropVal = (UPROPVAL*) new UPROPVAL[cPropIds])
|
|
if( rgpUPropInfo != NULL && rgUPropVal != NULL)
|
|
{
|
|
if( pCopyMe )
|
|
{
|
|
pCopyMe->CopyUPropInfo(iPropSet, rgpUPropInfo);
|
|
if( FAILED(hr = pCopyMe->CopyUPropVal(iPropSet, rgUPropVal)) )
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
// Clear Pointer Array
|
|
memset(rgpUPropInfo, 0, cPropIds * sizeof(UPROPINFO*));
|
|
|
|
// Set Pointer to correct property ids with a property set
|
|
pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo;
|
|
|
|
// Set up the writable property buffers
|
|
iNewDex = 0;
|
|
for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
|
|
{
|
|
if( pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
|
|
{
|
|
// Following ATLASSERT indicates that the are more
|
|
// writable properties then space allocated
|
|
ATLASSERT(iNewDex < cPropIds);
|
|
|
|
rgpUPropInfo[iNewDex] = &(pUPropInfo[ulPropId]);
|
|
rgUPropVal[iNewDex].dwOption = DBPROPOPTIONS_SETIFCHEAP;
|
|
rgUPropVal[iNewDex].pCColumnIds = NULL;
|
|
rgUPropVal[iNewDex].dwFlags = 0;
|
|
VariantInit(&(rgUPropVal[iNewDex].vValue));
|
|
GetDefaultValue(iPropSet, pUPropInfo[ulPropId].dwPropId,
|
|
&(rgUPropVal[iNewDex].dwOption), &(rgUPropVal[iNewDex].vValue));
|
|
iNewDex++;
|
|
}
|
|
}
|
|
|
|
ATLASSERT(cPropIds == iNewDex);
|
|
}
|
|
|
|
m_pUProp[iPropSet].rgpUPropInfo = rgpUPropInfo;
|
|
m_pUProp[iPropSet].pUPropVal = rgUPropVal;
|
|
m_pUProp[iPropSet].cPropIds = cPropIds;
|
|
}
|
|
else
|
|
{
|
|
delete[] rgpUPropInfo;
|
|
delete[] rgUPropVal;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Finally determine if there are any hidden property sets.. Those
|
|
// that do not show up in GetPropertyInfo and should not be returns on
|
|
// a 0, NULL call to GetProperties
|
|
for(iPropSet=0; iPropSet<m_cUPropSet; iPropSet++)
|
|
{
|
|
if( m_pUPropSet[iPropSet].dwFlags & UPROPSET_HIDDEN )
|
|
m_cUPropSetHidden++;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
//Check the arguments for Set Properties
|
|
static HRESULT SetPropertiesArgChk(const ULONG cPropertySets, const DBPROPSET rgPropertySets[])
|
|
{
|
|
if( cPropertySets > 0 && !rgPropertySets )
|
|
return E_INVALIDARG;
|
|
|
|
// New argument check for > 1 cPropertyIDs and NULL pointer for
|
|
// array of property ids.
|
|
for(ULONG ul=0; ul<cPropertySets; ul++)
|
|
{
|
|
if( rgPropertySets[ul].cProperties && !(rgPropertySets[ul].rgProperties) )
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
HRESULT GetProperties(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[],
|
|
ULONG* pcProperties, DBPROPSET** prgProperties,
|
|
const ULONG cSelectProps = 1, const GUID** ppGuid = NULL)
|
|
{
|
|
UPROPVAL* pUPropVal;
|
|
ULONG ulCurProp = 0;
|
|
ULONG cTmpPropertySets = cPropertySets;
|
|
HRESULT hr = S_OK;
|
|
ULONG ulSet = 0;
|
|
ULONG ulNext = 0;
|
|
ULONG cSets = 0;
|
|
ULONG cProps = 0;
|
|
ULONG ulProp = 0;
|
|
DWORD dwStatus = 0;
|
|
DBPROP* pProp = NULL;
|
|
DBPROP* pCurProp = NULL;
|
|
DBPROPSET* pPropSet = NULL;
|
|
UPROPINFO* pUPropInfo = NULL;
|
|
ULONG* piSetIndex = NULL;
|
|
ULONG* piIndex = NULL;
|
|
ULONG ulCurSet = 0;
|
|
ULONG iPropSet;
|
|
|
|
// ppGuid contains an array of GUIDs that the consumer can retrieve.
|
|
// This is based upon the interface calling this function
|
|
ATLASSERT(ppGuid != NULL);
|
|
|
|
// We need to have special handling for DBPROPSET_PROPERTIESINERROR..
|
|
// Turn on a flags to indicate this mode and make cTmpPropertySets
|
|
// appear to be 0
|
|
if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) &&
|
|
rgPropertySets &&
|
|
(rgPropertySets[0].guidPropertySet == DBPROPSET_PROPERTIESINERROR) )
|
|
{
|
|
cTmpPropertySets = 0;
|
|
dwStatus |= GETPROP_PROPSINERROR;
|
|
}
|
|
|
|
// If the consumer does not restrict the property sets
|
|
// by specify an array of property sets and a cTmpPropertySets
|
|
// greater than 0, then we need to make sure we
|
|
// have some to return
|
|
if( cTmpPropertySets == 0 )
|
|
{
|
|
// There are times when we are called from IRowsetInfo, ISessionProperties, etc.
|
|
// where we should return only the appropriate rowset when cTmpPropertySets is
|
|
// zero. This solves the problem if the user has more than one set specified in
|
|
// their PROPSET_MAP.
|
|
|
|
// Determine the number of property sets supported
|
|
if (ppGuid == NULL)
|
|
{
|
|
cSets = m_cUPropSet;
|
|
}
|
|
else
|
|
{
|
|
ULONG ulActualProps = 0;
|
|
piSetIndex = new ULONG[cSelectProps];
|
|
|
|
// Also, find the index for the set we are looking for
|
|
for (ULONG l=0; l<cSelectProps; l++)
|
|
{
|
|
for (piSetIndex[l]=0; piSetIndex[l]<m_cUPropSet; piSetIndex[l]++)
|
|
{
|
|
if (InlineIsEqualGUID(*m_pUPropSet[piSetIndex[l]].pPropSet, *ppGuid[l]))
|
|
{
|
|
ulActualProps++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// YIKES!
|
|
cSets = ulActualProps;
|
|
ulActualProps = 0;
|
|
piIndex = new ULONG[cSets];
|
|
for (l=0; l<cSelectProps; l++)
|
|
{
|
|
if (piSetIndex[l] != m_cUPropSet) // this is an invalid index
|
|
piIndex[ulActualProps++] = piSetIndex[l];
|
|
}
|
|
|
|
delete piSetIndex;
|
|
piSetIndex = NULL;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Since special property set guids are not supported by
|
|
// GetProperties, we can just use the count of property
|
|
// sets given to us.
|
|
cSets = cTmpPropertySets;
|
|
}
|
|
|
|
// If no properties set, then return
|
|
if( cSets == 0 )
|
|
return S_OK;
|
|
|
|
// Allocate the DBPROPSET structures
|
|
pPropSet = (DBPROPSET*)CoTaskMemAlloc(cSets * sizeof(DBPROPSET));
|
|
if(pPropSet)
|
|
{
|
|
memset(pPropSet, 0, cSets * sizeof(DBPROPSET));
|
|
|
|
// Fill in the output array
|
|
iPropSet = 0;
|
|
for(ulSet=0; ulSet<cSets; ulSet++)
|
|
{
|
|
// Depending of if Property sets are specified store the
|
|
// return property set.
|
|
if( cTmpPropertySets == 0 )
|
|
{
|
|
ULONG lSet;
|
|
|
|
if (ppGuid[ulSet] == NULL)
|
|
lSet = ulSet;
|
|
else
|
|
lSet = piIndex[ulSet];
|
|
if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN )
|
|
continue;
|
|
|
|
pPropSet[iPropSet].guidPropertySet = *(m_pUPropSet[lSet].pPropSet);
|
|
}
|
|
else
|
|
pPropSet[iPropSet].guidPropertySet = rgPropertySets[ulSet].guidPropertySet;
|
|
|
|
iPropSet++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROPSET array for GetProperties\n");
|
|
delete piIndex;
|
|
piIndex = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Process requested or derived Property sets
|
|
iPropSet=0;
|
|
for(ulSet=0; ulSet<cSets; ulSet++)
|
|
{
|
|
cProps = 0;
|
|
pProp = NULL;
|
|
ulNext = 0;
|
|
dwStatus &= (GETPROP_ERRORSOCCURRED | GETPROP_VALIDPROP | GETPROP_PROPSINERROR);
|
|
|
|
// Calculate the number of property nodes needed for this
|
|
// property set.
|
|
if( cTmpPropertySets == 0 )
|
|
{
|
|
ULONG lSet;
|
|
|
|
if (ppGuid[ulSet] == NULL)
|
|
lSet = ulSet;
|
|
else
|
|
lSet = piIndex[ulSet];
|
|
|
|
// If processing requesting all property sets, do not
|
|
// return the hidden sets.
|
|
if( m_pUPropSet[lSet].dwFlags & UPROPSET_HIDDEN )
|
|
continue;
|
|
|
|
cProps = m_pUPropSet[lSet].cUPropInfo;
|
|
|
|
// Add Enough space for node that are colid specific
|
|
cProps += GetCountofColids(&(m_pUProp[lSet]));
|
|
dwStatus |= GETPROP_ALLPROPIDS;
|
|
ulCurSet = lSet;
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT(ulSet == iPropSet);
|
|
|
|
// If the count of PROPIDs is 0 or It is a special property set, then
|
|
// the consumer is requesting all propids for this property set.
|
|
if(rgPropertySets[ulSet].cPropertyIDs == 0)
|
|
{
|
|
dwStatus |= GETPROP_ALLPROPIDS;
|
|
// We have to determine if the property set is supported and if so
|
|
// the count of properties in the set.
|
|
BOOL bAvailable = false;
|
|
for (ULONG l=0; l<cSelectProps; l++)
|
|
{
|
|
if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
|
|
bAvailable |= true;
|
|
}
|
|
|
|
if (bAvailable &&
|
|
GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) == S_OK)
|
|
{
|
|
cProps += m_pUPropSet[ulCurSet].cUPropInfo;
|
|
// Add Enough space for node that are colid specific
|
|
cProps += GetCountofColids(&m_pUProp[ulCurSet]);
|
|
}
|
|
else
|
|
{
|
|
// Not Supported
|
|
dwStatus |= GETPROP_ERRORSOCCURRED;
|
|
goto NEXT_SET;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cProps = rgPropertySets[ulSet].cPropertyIDs;
|
|
// Check to see if this is a supported interface based on ppGuid.
|
|
BOOL bAvailable = false;
|
|
for (ULONG l=0; l<cSelectProps; l++)
|
|
{
|
|
if (InlineIsEqualGUID(*ppGuid[l], rgPropertySets[ulSet].guidPropertySet))
|
|
bAvailable |= true;
|
|
}
|
|
|
|
if (!bAvailable ||
|
|
(GetIndexofPropSet(&(pPropSet[iPropSet].guidPropertySet), &ulCurSet) != S_OK))
|
|
{
|
|
dwStatus |= GETPROP_NOTSUPPORTED;
|
|
dwStatus |= GETPROP_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Allocate DBPROP array
|
|
if( cProps == 0 ) //Possible with Hidden Passthrough sets
|
|
goto NEXT_SET;
|
|
|
|
pProp = (DBPROP*)CoTaskMemAlloc(cProps * sizeof(DBPROP));
|
|
if( pProp )
|
|
{
|
|
// Initialize Buffer
|
|
memset(pProp, 0, cProps * sizeof(DBPROP));
|
|
for(ulProp=0; ulProp<cProps; ulProp++)
|
|
{
|
|
VariantInit(&(pProp[ulProp].vValue));
|
|
if( dwStatus & GETPROP_NOTSUPPORTED )
|
|
{
|
|
// Not supported, thus we need to mark all as NOT_SUPPORTED
|
|
pProp[ulProp].dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
|
|
pProp[ulProp].dwStatus = DBPROPSTATUS_NOTSUPPORTED;
|
|
}
|
|
}
|
|
// Make sure we support the property set
|
|
if( dwStatus & GETPROP_NOTSUPPORTED )
|
|
{
|
|
ulNext = cProps;
|
|
goto NEXT_SET;
|
|
}
|
|
|
|
// Now that we have determined we can support the property set, we
|
|
// need to gather current property values
|
|
for(ulProp=0; ulProp<cProps; ulProp++)
|
|
{
|
|
pCurProp = &(pProp[ulNext]);
|
|
|
|
//Initialize Variant Value
|
|
pCurProp->dwStatus = DBPROPSTATUS_OK;
|
|
|
|
// Retrieve current value of properties
|
|
if( dwStatus & GETPROP_ALLPROPIDS )
|
|
{
|
|
// Verify property is supported, if not do not return
|
|
if( !TESTBIT(&(m_rgdwSupported[ulCurSet * m_cElemPerSupported]), ulProp) )
|
|
continue;
|
|
|
|
// If we are looking for properties in error, then we should ignore all
|
|
// that are not in error.
|
|
if( (dwStatus & GETPROP_PROPSINERROR) &&
|
|
!TESTBIT(&(m_rgdwPropsInError[ulCurSet * m_cElemPerSupported]), ulProp) )
|
|
continue;
|
|
|
|
pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulProp]);
|
|
|
|
ATLASSERT( pUPropInfo );
|
|
|
|
pCurProp->dwPropertyID = pUPropInfo->dwPropId;
|
|
pCurProp->colid = DB_NULLID;
|
|
|
|
// If the property is WRITEABLE or CHANGABLE, then the value will
|
|
// be gotten from the UPROPVAL array, else it will be
|
|
// derive from the GetDefaultValue
|
|
if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
|
|
{
|
|
pUPropVal = &(m_pUProp[ulCurSet].
|
|
pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
|
|
ATLASSERT( pUPropVal );
|
|
|
|
// Check to see if this property supports column level,
|
|
// if so, dump those nodes
|
|
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
|
|
{
|
|
if( pUPropVal->pCColumnIds )
|
|
{
|
|
RetrieveColumnIdProps(pProp, pUPropVal, &ulNext);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pCurProp->dwOptions = pUPropVal->dwOption;
|
|
hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
|
|
}
|
|
else
|
|
{
|
|
GetDefaultValue(ulCurSet, pUPropInfo->dwPropId,
|
|
&(pCurProp->dwOptions), &(pCurProp->vValue));
|
|
}
|
|
|
|
// Return all Properties in Error with CONFLICT status
|
|
if( dwStatus & GETPROP_PROPSINERROR )
|
|
pCurProp->dwStatus = DBPROPSTATUS_CONFLICTING;
|
|
|
|
dwStatus |= GETPROP_VALIDPROP;
|
|
}
|
|
else
|
|
{
|
|
// Process Properties based on Restriction array.
|
|
|
|
pCurProp->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp];
|
|
pCurProp->colid = DB_NULLID;
|
|
|
|
if( GetIndexofPropIdinPropSet(ulCurSet, pCurProp->dwPropertyID,
|
|
&ulCurProp) == S_OK)
|
|
{
|
|
// Supported
|
|
pUPropInfo = &(m_pUPropSet[ulCurSet].pUPropInfo[ulCurProp]);
|
|
ATLASSERT( pUPropInfo );
|
|
|
|
// If the property is WRITEABLE, then the value will
|
|
// be gotten from the UPROPVAL array, else it will be
|
|
// derive from the GetDefaultValue
|
|
if( pUPropInfo->dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
|
|
{
|
|
pUPropVal = &(m_pUProp[ulCurSet].
|
|
pUPropVal[GetUPropValIndex(ulCurSet, pCurProp->dwPropertyID)]);
|
|
ATLASSERT( pUPropVal );
|
|
|
|
// Check to see if this property supports column level,
|
|
// if so, dump those nodes
|
|
if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK )
|
|
{
|
|
if( pUPropVal->pCColumnIds )
|
|
{
|
|
RetrieveColumnIdProps(pProp, pUPropVal, &ulNext);
|
|
continue;
|
|
}
|
|
}
|
|
pCurProp->dwOptions = pUPropVal->dwOption;
|
|
hr = VariantCopy(&(pCurProp->vValue), &(pUPropVal->vValue));
|
|
}
|
|
else
|
|
{
|
|
GetDefaultValue(ulCurSet, pUPropInfo->dwPropId,
|
|
&(pCurProp->dwOptions), &(pCurProp->vValue));
|
|
|
|
}
|
|
|
|
dwStatus |= GETPROP_VALIDPROP;
|
|
}
|
|
else
|
|
{
|
|
// Not Supported
|
|
pCurProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED;
|
|
dwStatus |= GETPROP_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
|
|
// Increment return nodes count
|
|
ulNext++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Could not allocate DBPROP array for GetProperties\n");
|
|
if( pPropSet )
|
|
{
|
|
// Free any DBPROP arrays
|
|
for(ulSet=0; ulSet<cSets; ulSet++)
|
|
{
|
|
// Need to loop through all the VARIANTS and clear them
|
|
for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++)
|
|
VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
|
|
if( pPropSet[ulSet].rgProperties )
|
|
CoTaskMemFree(pPropSet[ulSet].rgProperties);
|
|
}
|
|
|
|
// Free DBPROPSET
|
|
CoTaskMemFree(pPropSet);
|
|
}
|
|
//Since we have no properties to return, then we
|
|
//need to free allocated memory and return 0,NULL
|
|
if(pPropSet)
|
|
{
|
|
// Free any DBPROP arrays
|
|
for(ulSet=0; ulSet<cSets; ulSet++)
|
|
{
|
|
// Need to loop through all the VARIANTS and clear them
|
|
for(ulProp=0; ulProp<pPropSet[ulSet].cProperties; ulProp++)
|
|
VariantClear(&(pPropSet[ulSet].rgProperties[ulProp].vValue));
|
|
if( pPropSet[ulSet].rgProperties )
|
|
CoTaskMemFree(pPropSet[ulSet].rgProperties);
|
|
}
|
|
|
|
// Free DBPROPSET
|
|
CoTaskMemFree(pPropSet);
|
|
}
|
|
*pcProperties = 0;
|
|
*prgProperties = NULL;
|
|
delete piIndex;
|
|
piIndex = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
NEXT_SET:
|
|
// It is possible that all properties are not supported,
|
|
// thus we should delete that memory and set rgProperties
|
|
// to NULL
|
|
if( ulNext == 0 && pProp )
|
|
{
|
|
CoTaskMemFree(pProp);
|
|
pProp = NULL;
|
|
}
|
|
|
|
pPropSet[iPropSet].cProperties = ulNext;
|
|
pPropSet[iPropSet].rgProperties = pProp;
|
|
iPropSet++;
|
|
}
|
|
|
|
*pcProperties = iPropSet;
|
|
*prgProperties = pPropSet;
|
|
|
|
delete piIndex;
|
|
piIndex = NULL;
|
|
|
|
// At least one propid was marked as not S_OK
|
|
if( dwStatus & GETPROP_ERRORSOCCURRED )
|
|
{
|
|
// If at least 1 property was set
|
|
if( dwStatus & GETPROP_VALIDPROP )
|
|
return DB_S_ERRORSOCCURRED;
|
|
else
|
|
{
|
|
// Do not free any of the memory on a DB_E_
|
|
return DB_E_ERRORSOCCURRED;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG GetCountofColids(UPROP* pUProp)
|
|
{
|
|
ULONG cExtra=0;
|
|
ATLASSERT(pUProp);
|
|
for(ULONG ul=0; ul<pUProp->cPropIds; ul++)
|
|
{
|
|
if( pUProp->pUPropVal[ul].pCColumnIds )
|
|
cExtra += (pUProp->pUPropVal[ul].pCColumnIds)->GetCountOfPropColids();
|
|
}
|
|
return cExtra;
|
|
}
|
|
|
|
ULONG GetUPropValIndex(ULONG iCurSet, DBPROPID dwPropId)
|
|
{
|
|
for(ULONG ul=0; ul<m_pUProp[iCurSet].cPropIds; ul++)
|
|
{
|
|
if( (m_pUProp[iCurSet].rgpUPropInfo[ul])->dwPropId == dwPropId )
|
|
return ul;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void RetrieveColumnIdProps(DBPROP* pCurProp, UPROPVAL* pUPropVal, ULONG* pulNext)
|
|
{
|
|
// Reset to first Node
|
|
CColumnIds* pColIds = pUPropVal->pCColumnIds;
|
|
HRESULT hr = E_FAIL;
|
|
for (int i = 0; i < pColIds->GetSize(); i++)
|
|
{
|
|
CPropColID colId;
|
|
hr = pColIds->GetValue(i, &(pCurProp->dwOptions), &(pCurProp->colid),&(pCurProp->vValue));
|
|
if (SUCCEEDED(hr))
|
|
pCurProp = &(pCurProp[++(*pulNext)]);
|
|
}
|
|
(*pulNext)++;
|
|
}
|
|
|
|
//Check the arguments for Retrieve Properties
|
|
HRESULT GetPropertiesArgChk(const ULONG cPropertySets, const DBPROPIDSET rgPropertySets[],
|
|
ULONG* pcProperties, DBPROPSET** prgProperties)
|
|
{
|
|
// Initialize values
|
|
if(pcProperties)
|
|
*pcProperties = 0;
|
|
if(prgProperties)
|
|
*prgProperties = NULL;
|
|
|
|
// Check Arguments
|
|
if( ((cPropertySets > 0) && !rgPropertySets) || !pcProperties || !prgProperties )
|
|
return E_INVALIDARG;
|
|
|
|
// New argument check for > 1 cPropertyIDs and NULL pointer for
|
|
// array of property ids.
|
|
for(ULONG ul=0; ul<cPropertySets; ul++)
|
|
{
|
|
if( rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs) )
|
|
return E_INVALIDARG;
|
|
|
|
// Check for propper formation of DBPROPSET_PROPERTIESINERROR
|
|
if( (m_dwFlags & ARGCHK_PROPERTIESINERROR) &&
|
|
rgPropertySets[ul].guidPropertySet == DBPROPSET_PROPERTIESINERROR )
|
|
{
|
|
if( (cPropertySets > 1) ||
|
|
(rgPropertySets[ul].cPropertyIDs != 0) ||
|
|
(rgPropertySets[ul].rgPropertyIDs != NULL) )
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
OUT_OF_LINE HRESULT FInit(CUtlPropsBase* pCopyMe = NULL) = 0;
|
|
};
|
|
|
|
// Implementation Class
|
|
template <class T>
|
|
class ATL_NO_VTABLE CUtlProps : public CUtlPropsBase
|
|
{
|
|
public:
|
|
|
|
CUtlProps(DWORD dwFlags = 0)
|
|
{
|
|
ClearMemberVars();
|
|
m_dwFlags = dwFlags;
|
|
}
|
|
~CUtlProps()
|
|
{
|
|
FreeMemory();
|
|
}
|
|
void FreeMemory()
|
|
{
|
|
// Remove Property Information
|
|
if( m_pUProp )
|
|
{
|
|
for(ULONG ulPropSet=0; ulPropSet<m_cUPropSet; ulPropSet++)
|
|
{
|
|
UPROPVAL* pUPropVal = m_pUProp[ulPropSet].pUPropVal;
|
|
for(ULONG ulPropId=0; ulPropId<m_pUProp[ulPropSet].cPropIds; ulPropId++)
|
|
{
|
|
delete pUPropVal[ulPropId].pCColumnIds;
|
|
VariantClear(&(pUPropVal[ulPropId].vValue));
|
|
}
|
|
delete[] m_pUProp[ulPropSet].rgpUPropInfo;
|
|
delete[] m_pUProp[ulPropSet].pUPropVal;
|
|
}
|
|
|
|
}
|
|
|
|
delete[] m_pUProp;
|
|
delete[] m_rgdwSupported;
|
|
delete[] m_rgdwPropsInError;
|
|
delete[] m_rgiPropSetDex;
|
|
|
|
if (m_pUPropSet != NULL)
|
|
CoTaskMemFree(m_pUPropSet);
|
|
|
|
ClearMemberVars();
|
|
}
|
|
void ClearMemberVars()
|
|
{
|
|
m_cPropSetDex = 0;
|
|
m_cUPropSet = 0;
|
|
m_cUPropSetHidden = 0;
|
|
m_pUPropSet = NULL;
|
|
|
|
m_dwFlags = 0;
|
|
|
|
m_pUProp = NULL;
|
|
m_cElemPerSupported = 0;
|
|
m_rgdwSupported = NULL;
|
|
m_rgdwPropsInError = NULL;
|
|
m_rgiPropSetDex = NULL;
|
|
}
|
|
|
|
//Retrieve the property set indexes that match this property set.
|
|
HRESULT GetPropertySetIndex(GUID* pPropertySet)
|
|
{
|
|
DWORD dwFlag = 0;
|
|
ULONG ulSet;
|
|
|
|
ATLASSERT( m_cUPropSet && m_pUPropSet );
|
|
ATLASSERT( m_rgiPropSetDex );
|
|
ATLASSERT( pPropertySet );
|
|
|
|
m_cPropSetDex = 0;
|
|
|
|
if( *pPropertySet == DBPROPSET_DATASOURCEALL )
|
|
{
|
|
dwFlag = DBPROPFLAGS_DATASOURCE;
|
|
}
|
|
else if( *pPropertySet == DBPROPSET_DATASOURCEINFOALL )
|
|
{
|
|
dwFlag = DBPROPFLAGS_DATASOURCEINFO;
|
|
}
|
|
else if( *pPropertySet == DBPROPSET_ROWSETALL )
|
|
{
|
|
dwFlag = DBPROPFLAGS_ROWSET;
|
|
}
|
|
else if( *pPropertySet == DBPROPSET_DBINITALL )
|
|
{
|
|
dwFlag = DBPROPFLAGS_DBINIT;
|
|
}
|
|
else if( *pPropertySet == DBPROPSET_SESSIONALL )
|
|
{
|
|
dwFlag = DBPROPFLAGS_SESSION;
|
|
}
|
|
else // No scan required, just look for match.
|
|
{
|
|
for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
|
|
{
|
|
if( *(m_pUPropSet[ulSet].pPropSet) == *pPropertySet )
|
|
{
|
|
m_rgiPropSetDex[m_cPropSetDex] = ulSet;
|
|
m_cPropSetDex++;
|
|
break;
|
|
}
|
|
}
|
|
goto EXIT;
|
|
}
|
|
|
|
// Scan through the property sets looking for matching attributes
|
|
for(ulSet=0; ulSet<m_cUPropSet; ulSet++)
|
|
{
|
|
if( m_pUPropSet[ulSet].pUPropInfo[0].dwFlags & dwFlag )
|
|
{
|
|
m_rgiPropSetDex[m_cPropSetDex] = ulSet;
|
|
m_cPropSetDex++;
|
|
}
|
|
}
|
|
|
|
EXIT:
|
|
return (m_cPropSetDex) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
OUT_OF_LINE HRESULT GetDefaultValue(ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar)
|
|
{
|
|
return InternalGetDefaultValue(T::_GetPropSet, iPropSet, dwPropId, pdwOption, pVar);
|
|
}
|
|
|
|
OUT_OF_LINE HRESULT FInit(CUtlPropsBase* pCopyMe = NULL)
|
|
{
|
|
return InternalFInit(T::_GetPropSet, pCopyMe);
|
|
}
|
|
HRESULT FillDefaultValues(ULONG ulPropSetTarget = ULONG_MAX)
|
|
{
|
|
HRESULT hr;
|
|
ULONG ulPropId;
|
|
ULONG iPropSet;
|
|
ULONG iNewDex;
|
|
|
|
// Fill in all the actual values.
|
|
// Typically because we now have an hdbc with which to get them.
|
|
// (Or we no longer have an hdbc, so must clear them.)
|
|
// Note that the UPROP (with values) array may be a subset of the UPROPINFO array.
|
|
// Only writable properties are in UPROP array.
|
|
|
|
// Maybe restrict to a single PropSet if within valid range [0...m_cUPropSet-1].
|
|
// Otherwise do all propsets.
|
|
iPropSet = (ulPropSetTarget < m_cUPropSet) ? ulPropSetTarget : 0;
|
|
|
|
for( ; iPropSet<m_cUPropSet; iPropSet++)
|
|
{
|
|
iNewDex = 0;
|
|
for(ulPropId=0; ulPropId<m_pUPropSet[iPropSet].cUPropInfo; ulPropId++)
|
|
{
|
|
if( m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
|
|
{
|
|
//Initialize dwFlags element of UPropVal
|
|
m_pUProp[iPropSet].pUPropVal[iNewDex].dwFlags = 0;
|
|
|
|
// Don't need this since SetProperties() resets these.
|
|
//ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption == DBPROPOPTIONS_SETIFCHEAP);
|
|
ATLASSERT( m_pUProp[iPropSet].pUPropVal[iNewDex].pCColumnIds == NULL);
|
|
|
|
VariantClear(&m_pUProp[iPropSet].pUPropVal[iNewDex].vValue);
|
|
hr = GetDefaultValue(
|
|
iPropSet,
|
|
m_pUPropSet[iPropSet].pUPropInfo[ulPropId].dwPropId,
|
|
&m_pUProp[iPropSet].pUPropVal[iNewDex].dwOption,
|
|
&m_pUProp[iPropSet].pUPropVal[iNewDex].vValue );
|
|
if (FAILED(hr))
|
|
return hr;
|
|
iNewDex++;
|
|
}
|
|
}
|
|
|
|
// We're through if restricting to single PropSet.
|
|
if (ulPropSetTarget < m_cUPropSet)
|
|
break;
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
// Translate Rowset IIDs to PROPSET structures ready to pass to SetProperties
|
|
HRESULT ConvertRowsetIIDtoDBPROPSET(const IID* piid, DBPROPSET* pPropSet)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DBPROP* pProp;
|
|
|
|
ATLASSERT( piid || pPropSet );
|
|
ATLASSERT( (pPropSet->cProperties == 1) || (pPropSet->rgProperties) );
|
|
|
|
pProp = &(pPropSet->rgProperties[0]);
|
|
|
|
if(InlineIsEqualGUID(*piid, IID_IAccessor))
|
|
pProp->dwPropertyID = DBPROP_IAccessor;
|
|
else if(InlineIsEqualGUID(*piid,IID_IColumnsInfo))
|
|
pProp->dwPropertyID = DBPROP_IColumnsInfo;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowset))
|
|
pProp->dwPropertyID = DBPROP_IRowset;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetInfo))
|
|
pProp->dwPropertyID = DBPROP_IRowsetInfo;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetLocate))
|
|
pProp->dwPropertyID = DBPROP_IRowsetLocate;
|
|
else if(InlineIsEqualGUID(*piid , IID_IColumnsRowset))
|
|
pProp->dwPropertyID = DBPROP_IColumnsRowset;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetResynch))
|
|
pProp->dwPropertyID = DBPROP_IRowsetResynch;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetScroll))
|
|
pProp->dwPropertyID = DBPROP_IRowsetScroll;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetChange))
|
|
pProp->dwPropertyID = DBPROP_IRowsetChange;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetUpdate))
|
|
pProp->dwPropertyID = DBPROP_IRowsetUpdate;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetIdentity))
|
|
pProp->dwPropertyID = DBPROP_IRowsetIdentity;
|
|
else if(InlineIsEqualGUID(*piid , IID_IConnectionPointContainer))
|
|
pProp->dwPropertyID = DBPROP_IConnectionPointContainer;
|
|
else if(InlineIsEqualGUID(*piid , IID_ISupportErrorInfo))
|
|
pProp->dwPropertyID = DBPROP_ISupportErrorInfo;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetIndex))
|
|
pProp->dwPropertyID = DBPROP_IRowsetIndex;
|
|
#if( OLEDBVER >= 0x0200 )
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetLockRows))
|
|
pProp->dwPropertyID = DBPROP_IRowsetLockRows;
|
|
else if(InlineIsEqualGUID(*piid , IID_IProvideMoniker))
|
|
pProp->dwPropertyID = DBPROP_IProvideMoniker;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetNotify))
|
|
pProp->dwPropertyID = DBPROP_IRowsetNotify;
|
|
else if(InlineIsEqualGUID(*piid , IID_IReadData))
|
|
pProp->dwPropertyID = DBPROP_IReadData;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetExactScroll))
|
|
pProp->dwPropertyID = DBPROP_IRowsetExactScroll;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetNextRowset))
|
|
pProp->dwPropertyID = DBPROP_IRowsetNextRowset;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetDelete))
|
|
pProp->dwPropertyID = DBPROP_IRowsetDelete;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetDeleteBookmarks))
|
|
pProp->dwPropertyID = DBPROP_IRowsetDeleteBookmarks;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRow))
|
|
pProp->dwPropertyID = DBPROP_IRowsetNewRow;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetNewRowAfter))
|
|
pProp->dwPropertyID = DBPROP_IRowsetNewRowAfter;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetWithParameters))
|
|
pProp->dwPropertyID = DBPROP_IRowsetWithParameters;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetFind))
|
|
pProp->dwPropertyID = DBPROP_IRowsetFind;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetAsynch))
|
|
pProp->dwPropertyID = DBPROP_IRowsetAsynch;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetKeys))
|
|
pProp->dwPropertyID = DBPROP_IRowsetKeys;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchAll))
|
|
pProp->dwPropertyID = DBPROP_IRowsetWatchAll;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchNotify))
|
|
pProp->dwPropertyID = DBPROP_IRowsetWatchNotify;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetWatchRegion))
|
|
pProp->dwPropertyID = DBPROP_IRowsetWatchRegion;
|
|
else if(InlineIsEqualGUID(*piid , IID_IRowsetCopyRows))
|
|
pProp->dwPropertyID = DBPROP_IRowsetCopyRows;
|
|
#endif //#if( OLEDBVER >= 0x0200 )
|
|
else
|
|
hr = S_FALSE;
|
|
|
|
// If the IID can be mapped to a DBPROPID, the
|
|
// we need to initialize the vValue to TRUE
|
|
if(hr == S_OK)
|
|
{
|
|
// Set PropertySet
|
|
pPropSet->guidPropertySet = DBPROPSET_ROWSET;
|
|
|
|
// Set Property
|
|
pProp->dwOptions = DBPROPOPTIONS_REQUIRED;
|
|
pProp->dwStatus = 0;
|
|
pProp->colid = DB_NULLID;
|
|
|
|
VariantInit(&(pProp->vValue));
|
|
pProp->vValue.vt = VT_BOOL;
|
|
V_BOOL(&(pProp->vValue)) = VARIANT_TRUE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
void SetPropertyInError(const ULONG iPropSet, const ULONG iPropId)
|
|
{
|
|
SETBIT(&(m_rgdwPropsInError[iPropSet * m_cElemPerSupported]), iPropId);
|
|
}
|
|
|
|
BOOL IsPropSet(const GUID* pguidPropSet, DBPROPID dwPropId)
|
|
{
|
|
HRESULT hr;
|
|
ULONG iPropSet;
|
|
ULONG iPropId;
|
|
VARIANT vValue;
|
|
DWORD dwOptions;
|
|
|
|
VariantInit(&vValue);
|
|
|
|
if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
|
|
{
|
|
if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
|
|
{
|
|
if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags &
|
|
(DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
|
|
{
|
|
ULONG iPropVal = GetUPropValIndex(iPropSet, dwPropId);
|
|
|
|
dwOptions = m_pUProp[iPropSet].pUPropVal[iPropVal].dwOption;
|
|
hr = VariantCopy(&vValue, &(m_pUProp[iPropSet].
|
|
pUPropVal[iPropVal].vValue));
|
|
}
|
|
else
|
|
{
|
|
hr = GetDefaultValue(iPropSet, dwPropId,
|
|
&dwOptions, &vValue);
|
|
}
|
|
|
|
if( dwOptions == DBPROPOPTIONS_REQUIRED )
|
|
{
|
|
ATLASSERT( vValue.vt == VT_BOOL );
|
|
if( SUCCEEDED(hr) &&
|
|
(V_BOOL(&vValue) == VARIANT_TRUE) )
|
|
{
|
|
VariantClear(&vValue);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VariantClear(&vValue);
|
|
return FALSE;
|
|
}
|
|
OUT_OF_LINE HRESULT GetPropValue(const GUID* pguidPropSet, DBPROPID dwPropId, VARIANT* pvValue)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ULONG iPropSet;
|
|
ULONG iPropId = 0;
|
|
DWORD dwOptions;
|
|
|
|
if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
|
|
{
|
|
if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
|
|
{
|
|
if( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) )
|
|
{
|
|
hr = VariantCopy(pvValue, &(m_pUProp[iPropSet].pUPropVal[
|
|
GetUPropValIndex(iPropSet, dwPropId)].vValue));
|
|
}
|
|
else
|
|
{
|
|
VariantClear(pvValue);
|
|
|
|
hr = GetDefaultValue(iPropSet, dwPropId,
|
|
&dwOptions, pvValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
HRESULT SetPropValue(const GUID* pguidPropSet,DBPROPID dwPropId, VARIANT* pvValue)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
ULONG iPropSet;
|
|
ULONG iPropId;
|
|
|
|
if( GetIndexofPropSet(pguidPropSet, &iPropSet) == S_OK )
|
|
{
|
|
if( GetIndexofPropIdinPropSet(iPropSet, dwPropId, &iPropId) == S_OK )
|
|
{
|
|
ATLASSERT( m_pUPropSet[iPropSet].pUPropInfo[iPropId].dwFlags & (DBPROPFLAGS_WRITE | DBPROPFLAGS_CHANGE) );
|
|
|
|
hr = VariantCopy(&(m_pUProp[iPropSet].pUPropVal[
|
|
GetUPropValIndex(iPropSet, dwPropId)].vValue), pvValue);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//Pointer to properties in error mask
|
|
DWORD* GetPropsInErrorPtr(){return m_rgdwPropsInError;}
|
|
ULONG GetUPropSetCount() {return m_cUPropSet;}
|
|
void SetUPropSetCount(ULONG c) {m_cUPropSet = c;}
|
|
|
|
// NOTE: The following functions depend on all prior
|
|
// properties in the array being writable.
|
|
// This is because the UPROP array contains only writable elements,
|
|
// and the UPROPINFO array contains writable and read-only elements.
|
|
// (If this is a problem, we would need to define which one it came from
|
|
// and add the appropriate ATLASSERTs...)
|
|
|
|
//Get DBPROPOPTIONS_xx
|
|
DWORD GetPropOption(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
return m_pUProp[iPropSet].pUPropVal[iProp].dwOption;
|
|
}
|
|
//Set DBPROPOPTIONS_xx
|
|
void SetPropOption(ULONG iPropSet, ULONG iProp, DWORD dwOption)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
m_pUProp[iPropSet].pUPropVal[iProp].dwOption = dwOption;
|
|
}
|
|
//Determine if property is required and variant_true
|
|
BOOL IsRequiredTrue(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL);
|
|
ATLASSERT(V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE
|
|
|| V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_FALSE);
|
|
|
|
return( (m_pUProp[iPropSet].pUPropVal[iProp].dwOption == DBPROPOPTIONS_REQUIRED) &&
|
|
(V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) == VARIANT_TRUE) );
|
|
}
|
|
DWORD GetInternalFlags(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
return m_pUProp[iPropSet].pUPropVal[iProp].dwFlags;
|
|
}
|
|
void AddInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
m_pUProp[iPropSet].pUPropVal[iProp].dwFlags |= dwFlags;
|
|
}
|
|
void RemoveInternalFlags(ULONG iPropSet, ULONG iProp, DWORD dwFlags)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
m_pUProp[iPropSet].pUPropVal[iProp].dwFlags &= ~dwFlags;
|
|
}
|
|
VARIANT * GetVariant(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
return & m_pUProp[iPropSet].pUPropVal[iProp].vValue;
|
|
}
|
|
HRESULT SetVariant(ULONG iPropSet, ULONG iProp, VARIANT *pv )
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
// Does VariantClear first.
|
|
return VariantCopy( &m_pUProp[iPropSet].pUPropVal[iProp].vValue, pv );
|
|
}
|
|
void SetValEmpty(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
VariantClear( &m_pUProp[iPropSet].pUPropVal[iProp].vValue );
|
|
}
|
|
BOOL IsEmpty(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
return ( m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_EMPTY);
|
|
}
|
|
void SetValBool(ULONG iPropSet, ULONG iProp, VARIANT_BOOL bVal)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
// Note that we accept any "true" value.
|
|
VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
|
|
m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_BOOL;
|
|
V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue) = (bVal ? VARIANT_TRUE : VARIANT_FALSE);
|
|
}
|
|
VARIANT_BOOL GetValBool(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BOOL);
|
|
return V_BOOL(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
|
|
}
|
|
void SetValShort(ULONG iPropSet, ULONG iProp, SHORT iVal )
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
|
|
m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I2;
|
|
m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal = iVal;
|
|
}
|
|
SHORT GetValShort(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I2);
|
|
return m_pUProp[iPropSet].pUPropVal[iProp].vValue.iVal;
|
|
}
|
|
void SetValLong(ULONG iPropSet, ULONG iProp, LONG lVal)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
VariantClear(&m_pUProp[iPropSet].pUPropVal[iProp].vValue);
|
|
m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt = VT_I4;
|
|
m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal = lVal;
|
|
}
|
|
LONG GetValLong(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_I4);
|
|
return m_pUProp[iPropSet].pUPropVal[iProp].vValue.lVal;
|
|
}
|
|
HRESULT SetValString(ULONG iPropSet, ULONG iProp, const WCHAR *pwsz)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
VARIANT *pv = &m_pUProp[iPropSet].pUPropVal[iProp].vValue;
|
|
VariantClear(pv);
|
|
pv->bstrVal = SysAllocString(pwsz);
|
|
if (pv->bstrVal)
|
|
pv->vt = VT_BSTR;
|
|
else
|
|
return E_FAIL;
|
|
|
|
// See if this was used for non-string type.
|
|
// Typically this is an easy way to pass integer as a string.
|
|
if (GetExpectedVarType(iPropSet,iProp) == VT_BSTR)
|
|
return NOERROR;
|
|
if (pwsz[0] != L'\0')
|
|
return VariantChangeType( pv, pv, 0, GetExpectedVarType(iPropSet,iProp) );
|
|
|
|
// Set to "", which for non-string means empty.
|
|
SysFreeString(pv->bstrVal);
|
|
pv->vt = VT_EMPTY;
|
|
return NOERROR;
|
|
}
|
|
const WCHAR * GetValString(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
ATLASSERT(m_pUProp[iPropSet].pUPropVal[iProp].vValue.vt == VT_BSTR);
|
|
return m_pUProp[iPropSet].pUPropVal[iProp].vValue.bstrVal;
|
|
}
|
|
const GUID * GetGuid(ULONG iPropSet)
|
|
{
|
|
ATLASSERT(iPropSet < m_cUPropSet);
|
|
return m_pUPropSet[iPropSet].pPropSet;
|
|
}
|
|
DWORD GetPropID(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
return m_pUPropSet[iPropSet].pUPropInfo[iProp].dwPropId;
|
|
}
|
|
VARTYPE GetExpectedVarType(ULONG iPropSet, ULONG iProp)
|
|
{
|
|
ATLASSERT(( (iPropSet < m_cUPropSet) && (iProp < m_pUPropSet[iPropSet].cUPropInfo) && (iProp < m_pUProp[iPropSet].cPropIds) ));
|
|
return m_pUPropSet[iPropSet].pUPropInfo[iProp].VarType;
|
|
}
|
|
virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet)
|
|
{
|
|
ATLASSERT(pPropSet && pulCurSet);
|
|
|
|
for(ULONG ul=0; ul<m_cUPropSet; ul++)
|
|
{
|
|
if( *pPropSet == *(m_pUPropSet[ul].pPropSet) )
|
|
{
|
|
*pulCurSet = ul;
|
|
return S_OK;
|
|
}
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
virtual HRESULT InitUPropSetsSupported()
|
|
{
|
|
return InternalInitUPropSetsSupported(T::_GetPropSet);
|
|
}
|
|
|
|
HRESULT GetIndexOfPropertyInSet(const GUID* pPropSet, DBPROPID dwPropertyId, ULONG* piCurPropId, ULONG* piCurSet)
|
|
{
|
|
HRESULT hr = GetIndexofPropSet(pPropSet, piCurSet);
|
|
if (hr == S_FALSE)
|
|
return hr;
|
|
UPROPINFO* pUPropInfo = m_pUPropSet[*piCurSet].pUPropInfo;
|
|
for(ULONG ul=0; ul<m_pUPropSet[*piCurSet].cUPropInfo; ul++)
|
|
{
|
|
if( dwPropertyId == pUPropInfo[ul].dwPropId )
|
|
*piCurPropId = ul;
|
|
return S_OK;
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
HRESULT SetSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId)
|
|
{
|
|
ULONG iCurPropId, iCurSet;
|
|
|
|
if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
|
|
{
|
|
m_rgdwSupported[iCurSet * m_cElemPerSupported] |= 1 << iCurPropId;
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT ClearSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId)
|
|
{
|
|
ULONG iCurPropId, iCurSet;
|
|
|
|
if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
|
|
{
|
|
m_rgdwSupported[iCurSet * m_cElemPerSupported] &= ~( 1 << iCurPropId);
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT TestSupportedBit(const GUID* pPropSet, DBPROPID dwPropertyId, bool& bSet)
|
|
{
|
|
ULONG iCurPropId, iCurSet;
|
|
|
|
if (GetIndexOfPropertyInSet(pPropSet, dwPropertyId, &iCurPropId, &iCurSet) == S_OK)
|
|
{
|
|
bSet = (m_rgdwSupported[iCurSet * m_cElemPerSupported] & ( 1 << iCurPropId)) != 0;
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
void CopyPropsInError(DWORD* rgdwSupported)
|
|
{
|
|
memcpy(rgdwSupported, m_rgdwPropsInError, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD));
|
|
}
|
|
};
|
|
|
|
// IDBPropertiesImpl
|
|
// IDBProperties <- IUnknown
|
|
template <class T>
|
|
class ATL_NO_VTABLE IDBPropertiesImpl : public IDBProperties, public CUtlProps<T>
|
|
{
|
|
public:
|
|
STDMETHOD(GetProperties)(ULONG cPropertySets,
|
|
const DBPROPIDSET rgPropertySets[],
|
|
ULONG *pcProperties,
|
|
DBPROPSET **prgProperties)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetProperties\n");
|
|
T* pT = (T*)this;
|
|
HRESULT hr = GetPropertiesArgChk(cPropertySets, rgPropertySets, pcProperties, prgProperties);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Check for other invalid arguments
|
|
for (ULONG i=0; i<cPropertySets; i++)
|
|
{
|
|
if (InlineIsEqualGUID(rgPropertySets[i].guidPropertySet, DBPROPSET_PROPERTIESINERROR))
|
|
if (pcProperties != NULL || prgProperties != NULL || cPropertySets > 1)
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
const GUID* ppGuid[3];
|
|
if (pT->m_dwStatus & DSF_INITIALIZED)
|
|
{
|
|
ppGuid[0] = &DBPROPSET_DBINIT;
|
|
ppGuid[1] = &DBPROPSET_DATASOURCE;
|
|
ppGuid[2] = &DBPROPSET_DATASOURCEINFO;
|
|
hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets,
|
|
pcProperties, prgProperties, 3, ppGuid);
|
|
}
|
|
else
|
|
{
|
|
ppGuid[0] = &DBPROPSET_DBINIT;
|
|
hr = CUtlProps<T>::GetProperties(cPropertySets, rgPropertySets,
|
|
pcProperties, prgProperties, 1, ppGuid);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(GetPropertyInfo)(ULONG cPropertySets,
|
|
const DBPROPIDSET rgPropertySets[],
|
|
ULONG *pcPropertyInfoSets,
|
|
DBPROPINFOSET **prgPropertyInfoSets,
|
|
OLECHAR **ppDescBuffer)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::GetPropertyInfo\n");
|
|
T* pT = (T*)this;
|
|
|
|
if (pT->m_pCUtlPropInfo == NULL)
|
|
{
|
|
// Go ahead and create the m_pCUtlPropInfo but do not change the
|
|
// Initialized status of the provider (see IDBInitialize::Initialize).
|
|
ATLTRACE2(atlTraceDBProvider, 0, "m_pCUtlPropInfo == NULL\n");
|
|
pT->Lock();
|
|
delete pT->m_pCUtlPropInfo;
|
|
ATLTRY(pT->m_pCUtlPropInfo = new CUtlPropInfo<T>())
|
|
pT->Unlock();
|
|
if (pT->m_pCUtlPropInfo == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBProperties::GetPropertyInfo Error : OOM\n");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
HRESULT hr = pT->m_pCUtlPropInfo->FInit();
|
|
if (hr != S_OK)
|
|
{
|
|
pT->Lock();
|
|
delete pT->m_pCUtlPropInfo;
|
|
pT->m_pCUtlPropInfo = NULL;
|
|
pT->Unlock();
|
|
}
|
|
}
|
|
|
|
// Initialize
|
|
if( pcPropertyInfoSets )
|
|
*pcPropertyInfoSets = 0;
|
|
if( prgPropertyInfoSets )
|
|
*prgPropertyInfoSets = NULL;
|
|
if( ppDescBuffer )
|
|
*ppDescBuffer = NULL;
|
|
|
|
// Check Arguments
|
|
if( ((cPropertySets > 0) && !rgPropertySets) ||
|
|
!pcPropertyInfoSets || !prgPropertyInfoSets )
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
// New argument check for > 1 cPropertyIDs and NULL pointer for
|
|
// array of property ids.
|
|
const DWORD SPECIAL_GROUP = 1;
|
|
const DWORD SPECIAL_SINGLE = 2;
|
|
const DWORD SPECIALS = SPECIAL_GROUP | SPECIAL_SINGLE;
|
|
DWORD dwSpecial = 0;
|
|
for(ULONG ul=0; ul<cPropertySets; ul++)
|
|
{
|
|
if( (rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEALL) ||
|
|
(rgPropertySets[ul].guidPropertySet == DBPROPSET_DATASOURCEINFOALL) ||
|
|
(rgPropertySets[ul].guidPropertySet == DBPROPSET_DBINITALL) ||
|
|
(rgPropertySets[ul].guidPropertySet == DBPROPSET_SESSIONALL) ||
|
|
(rgPropertySets[ul].guidPropertySet == DBPROPSET_ROWSETALL) )
|
|
dwSpecial |= SPECIAL_GROUP;
|
|
else
|
|
dwSpecial |= SPECIAL_SINGLE;
|
|
|
|
if( (dwSpecial == SPECIALS) ||
|
|
(rgPropertySets[ul].cPropertyIDs && !(rgPropertySets[ul].rgPropertyIDs)) )
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (pT->m_dwStatus & DSF_INITIALIZED)
|
|
return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets,
|
|
pcPropertyInfoSets, prgPropertyInfoSets,
|
|
ppDescBuffer, true);
|
|
else
|
|
return pT->m_pCUtlPropInfo->GetPropertyInfo(cPropertySets, rgPropertySets,
|
|
pcPropertyInfoSets, prgPropertyInfoSets,
|
|
ppDescBuffer, false, &DBPROPSET_DBINITALL);
|
|
|
|
}
|
|
|
|
STDMETHOD(SetProperties)(ULONG cPropertySets,
|
|
DBPROPSET rgPropertySets[])
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBPropertiesImpl::SetProperties\n");
|
|
HRESULT hr;
|
|
DBPROPSET* pdbPropSet = NULL;
|
|
ULONG iProp;
|
|
const GUID* ppGuid[3];
|
|
T* pT = (T*)this;
|
|
|
|
// Quick return if the Count of Properties is 0
|
|
if( cPropertySets == 0 )
|
|
return S_OK;
|
|
|
|
hr = CUtlProps<T>::SetPropertiesArgChk(cPropertySets, rgPropertySets);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// We need to handle the DBINIT properties specially after being initialized.
|
|
// - they should be treated as NOTSETTABLE at this point.
|
|
if( pT->m_dwStatus & DSF_INITIALIZED )
|
|
{
|
|
ATLASSERT(cPropertySets);
|
|
|
|
BOOL fFoundDBINIT = FALSE;
|
|
|
|
// Allocate a DBPROPSET structure of equal size
|
|
ATLTRY(pdbPropSet = new DBPROPSET[cPropertySets])
|
|
if( pdbPropSet == NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
for(ULONG iNewSet=0,iSet=0; iSet<cPropertySets; iSet++)
|
|
{
|
|
// Remove any DBPROPSET_DBINIT values and mark them all
|
|
// as not settable
|
|
if( (rgPropertySets[iSet].guidPropertySet == DBPROPSET_DBINIT))
|
|
{
|
|
fFoundDBINIT = TRUE;
|
|
for(iProp=0; iProp<rgPropertySets[iSet].cProperties; iProp++)
|
|
rgPropertySets[iSet].rgProperties[iProp].dwStatus = DBPROPSTATUS_NOTSETTABLE;
|
|
}
|
|
else
|
|
{
|
|
// If not DBPROPSET_DBINIT then copy the DBPROPSET values
|
|
memcpy(&pdbPropSet[iNewSet++], &rgPropertySets[iSet], sizeof(DBPROPSET));
|
|
}
|
|
}
|
|
|
|
// If we have no propertyset to pass on to the property handler, we
|
|
// can exit
|
|
if( iNewSet == 0 )
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
goto exit;
|
|
}
|
|
|
|
ppGuid[0] = &DBPROPSET_DBINIT;
|
|
ppGuid[1] = &DBPROPSET_DATASOURCE;
|
|
ppGuid[2] = &DBPROPSET_DATASOURCEINFO;
|
|
hr = CUtlProps<T>::SetProperties(0, iNewSet, pdbPropSet, 3, ppGuid);
|
|
|
|
// If we have determined that one of the property sets was DBINIT, we may
|
|
// need to fixup the returned hr value.
|
|
if( fFoundDBINIT && SUCCEEDED(hr))
|
|
hr = DB_S_ERRORSOCCURRED;
|
|
}
|
|
else
|
|
{
|
|
// Note that m_pCUtlProps knows about initialization,
|
|
// so we don't have to here.
|
|
ppGuid[0] = &DBPROPSET_DBINIT;
|
|
hr = CUtlProps<T>::SetProperties(0, cPropertySets, rgPropertySets,
|
|
1, ppGuid);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
delete[] pdbPropSet;
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
|
|
#define BEGIN_SCHEMA_MAP(SchemaClass) \
|
|
typedef SchemaClass _SchemaClass; \
|
|
HRESULT _SchemaSupport(GUID** ppGuid, \
|
|
IUnknown *pUnkOuter, \
|
|
REFIID rguidSchema, \
|
|
ULONG cRestrictions, \
|
|
const VARIANT rgRestrictions[], \
|
|
REFIID riid, \
|
|
ULONG cPropertySets, \
|
|
DBPROPSET rgPropertySets[], \
|
|
IUnknown **ppRowset) \
|
|
{ \
|
|
int cGuids = 0; \
|
|
HRESULT hr = S_OK; \
|
|
if (ppGuid != NULL) \
|
|
*ppGuid = NULL;
|
|
|
|
#define SCHEMA_ENTRY(guid, rowsetClass) \
|
|
if (ppGuid != NULL && SUCCEEDED(hr)) \
|
|
{ \
|
|
cGuids++; \
|
|
*ppGuid = (GUID*)CoTaskMemRealloc(*ppGuid, cGuids * sizeof(GUID)); \
|
|
hr = (*ppGuid == NULL) ? E_OUTOFMEMORY : S_OK; \
|
|
if (SUCCEEDED(hr)) \
|
|
(*ppGuid)[cGuids - 1] = guid; \
|
|
} \
|
|
else \
|
|
{ \
|
|
if (InlineIsEqualGUID(guid, rguidSchema)) \
|
|
{ \
|
|
rowsetClass* pRowset; \
|
|
hr = CreateSchemaRowset(pUnkOuter, cRestrictions, \
|
|
rgRestrictions, riid, cPropertySets, \
|
|
rgPropertySets, ppRowset, pRowset); \
|
|
return hr; \
|
|
} \
|
|
}
|
|
|
|
#define END_SCHEMA_MAP() \
|
|
if (ppGuid != NULL) \
|
|
return hr; \
|
|
return E_INVALIDARG; \
|
|
}
|
|
|
|
|
|
template <class SessionClass>
|
|
class ATL_NO_VTABLE IDBSchemaRowsetImpl: public IDBSchemaRowset
|
|
{
|
|
public:
|
|
|
|
OUT_OF_LINE HRESULT InternalCreateSchemaRowset(IUnknown *pUnkOuter, ULONG /*cRestrictions*/,
|
|
const VARIANT /*rgRestrictions*/[], REFIID riid,
|
|
ULONG cPropertySets, DBPROPSET rgPropertySets[],
|
|
IUnknown** ppRowset, IUnknown* pUnkThis, CUtlPropsBase* pProps,
|
|
IUnknown* pUnkSession)
|
|
{
|
|
HRESULT hr, hrProps = S_OK;
|
|
if (ppRowset != NULL)
|
|
*ppRowset = NULL;
|
|
if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
|
|
return DB_E_NOAGGREGATION;
|
|
CComPtr<IUnknown> spUnk;
|
|
hr = pUnkThis->QueryInterface(IID_IUnknown, (void**)&spUnk);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
hr = pProps->FInit();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
hr = pProps->SetPropertiesArgChk(cPropertySets, rgPropertySets);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
const GUID* ppGuid[1];
|
|
ppGuid[0] = &DBPROPSET_ROWSET;
|
|
|
|
// Call SetProperties. The true in the last parameter indicates
|
|
// the special behavior that takes place on rowset creation (i.e.
|
|
// it succeeds as long as any of the properties were not marked
|
|
// as DBPROPS_REQUIRED.
|
|
|
|
hrProps = pProps->SetProperties(0, cPropertySets, rgPropertySets,
|
|
1, ppGuid, true);
|
|
if (FAILED(hrProps))
|
|
return hrProps;
|
|
|
|
if (ppRowset == NULL)
|
|
return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
|
|
|
|
CComQIPtr<IObjectWithSite> spSite = spUnk;
|
|
ATLASSERT(spSite != NULL);
|
|
hr = spSite->SetSite(pUnkSession);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
if (InlineIsEqualGUID(riid, IID_NULL))
|
|
return E_NOINTERFACE;
|
|
hr = spUnk->QueryInterface(riid, (void**)ppRowset);
|
|
if (FAILED(hr))
|
|
{
|
|
*ppRowset = NULL;
|
|
return hr;
|
|
}
|
|
return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
|
|
}
|
|
|
|
template <class SchemaRowsetClass>
|
|
HRESULT CreateSchemaRowset(IUnknown *pUnkOuter, ULONG cRestrictions,
|
|
const VARIANT rgRestrictions[], REFIID riid,
|
|
ULONG cPropertySets, DBPROPSET rgPropertySets[],
|
|
IUnknown** ppRowset, SchemaRowsetClass*& pSchemaRowset)
|
|
{
|
|
HRESULT hrProps, hr = S_OK;
|
|
SessionClass* pT = (SessionClass*) this;
|
|
CComPolyObject<SchemaRowsetClass>* pPolyObj;
|
|
if (FAILED(hr = CComPolyObject<SchemaRowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
|
|
return hr;
|
|
pSchemaRowset = &(pPolyObj->m_contained);
|
|
hr = InternalCreateSchemaRowset(pUnkOuter, cRestrictions, rgRestrictions,
|
|
riid, cPropertySets, rgPropertySets, ppRowset,
|
|
pPolyObj, pT, pT->GetUnknown());
|
|
// Ref the created COM object and Auto release it on failure
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
hrProps = hr;
|
|
// Get a pointer to the Rowset instance
|
|
LONG cRowsAffected;
|
|
hr = pSchemaRowset->Execute(&cRowsAffected, cRestrictions, rgRestrictions);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
|
|
}
|
|
|
|
|
|
void SetRestrictions(ULONG cRestrictions, GUID* /*rguidSchema*/, ULONG* rgRestrictions)
|
|
{
|
|
memset(rgRestrictions, 0, sizeof(ULONG) * cRestrictions);
|
|
}
|
|
|
|
STDMETHOD(GetSchemas)(ULONG * pcSchemas, GUID ** prgSchemas, ULONG** prgRest)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetSchemas\n");
|
|
if (pcSchemas != NULL)
|
|
*pcSchemas = 0;
|
|
if (prgSchemas != NULL)
|
|
*prgSchemas = NULL;
|
|
if (pcSchemas == NULL || prgSchemas == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
SessionClass* pT = (SessionClass*)this;
|
|
|
|
HRESULT hr = pT->_SchemaSupport(prgSchemas, NULL, GUID_NULL, 0,
|
|
NULL, GUID_NULL, 0, NULL, NULL);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
CComPtr<IMalloc> spMalloc;
|
|
hr = CoGetMalloc(1, &spMalloc);
|
|
if (FAILED(hr))
|
|
{
|
|
CoTaskMemFree(*prgSchemas);
|
|
*prgSchemas = NULL;
|
|
return hr;
|
|
}
|
|
*pcSchemas = (ULONG)(ULONG_PTR)spMalloc->GetSize(*prgSchemas) / sizeof(GUID);
|
|
|
|
if (prgRest != NULL)
|
|
{
|
|
// The OLE DB spec states that if prgRest == NULL not to return array
|
|
// but it also says that is E_INVALIDARG, so doing first
|
|
*prgRest = (ULONG*) spMalloc->Alloc(sizeof(ULONG) * (*pcSchemas));
|
|
if (*prgRest == NULL)
|
|
{
|
|
spMalloc->Free(*prgSchemas);
|
|
*prgSchemas = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
pT->SetRestrictions(*pcSchemas, *prgSchemas, *prgRest);
|
|
}
|
|
return hr;
|
|
}
|
|
STDMETHOD(GetRowset)(IUnknown *pUnkOuter, REFGUID rguidSchema, ULONG cRestrictions,
|
|
const VARIANT rgRestrictions[], REFIID riid, ULONG cPropertySets,
|
|
DBPROPSET rgPropertySets[], IUnknown **ppRowset)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBSchemaRowsetImpl::GetRowset\n");
|
|
SessionClass* pT = (SessionClass*)this;
|
|
return pT->_SchemaSupport(NULL, pUnkOuter, rguidSchema, cRestrictions,
|
|
rgRestrictions, riid, cPropertySets,
|
|
rgPropertySets, ppRowset);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// IDBCreateCommandImpl
|
|
template <class T, class CommandClass>
|
|
class ATL_NO_VTABLE IDBCreateCommandImpl : public IDBCreateCommand
|
|
{
|
|
public:
|
|
STDMETHOD(CreateCommand)(IUnknown *pUnkOuter,
|
|
REFIID riid,
|
|
IUnknown **ppvCommand)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IDBCreateCommandImpl::CreateCommand\n");
|
|
if (ppvCommand == NULL)
|
|
return E_INVALIDARG;
|
|
HRESULT hr;
|
|
CComPolyObject<CommandClass>* pCommand;
|
|
|
|
// You can't QI for an interface other than IUnknown when aggregating
|
|
// and creating the object. You might ask for your own interface,
|
|
// which would be bad. Note, we return DB_E_NOAGGREGATION instead of
|
|
// CLASS_E_NOAGGREGATION due to OLE DB constraints.
|
|
if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid))
|
|
return DB_E_NOAGGREGATION;
|
|
|
|
hr = CComPolyObject<CommandClass>::CreateInstance(pUnkOuter, &pCommand);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
// Ref the created COM object and Auto release it on failure
|
|
CComPtr<IUnknown> spUnk;
|
|
hr = pCommand->QueryInterface(&spUnk);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pCommand; // must hand delete as it is not ref'd
|
|
return hr;
|
|
}
|
|
ATLASSERT(pCommand->m_contained.m_spUnkSite == NULL);
|
|
pCommand->m_contained.SetSite(this);
|
|
hr = pCommand->QueryInterface(riid, (void**)ppvCommand);
|
|
return hr;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
// IGetDataSourceImpl
|
|
template <class T>
|
|
class ATL_NO_VTABLE IGetDataSourceImpl : public IGetDataSource
|
|
{
|
|
public:
|
|
STDMETHOD(GetDataSource)(REFIID riid,
|
|
IUnknown **ppDataSource)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IGetDataSourceImpl::GetDataSource\n");
|
|
if (ppDataSource == NULL)
|
|
return E_INVALIDARG;
|
|
T* pT = (T*) this;
|
|
ATLASSERT(pT->m_spUnkSite != NULL);
|
|
return pT->m_spUnkSite->QueryInterface(riid, (void**)ppDataSource);
|
|
}
|
|
};
|
|
|
|
|
|
// IOpenRowsetImpl
|
|
template <class SessionClass>
|
|
class IOpenRowsetImpl : public IOpenRowset
|
|
{
|
|
public:
|
|
template <class RowsetClass>
|
|
HRESULT CreateRowset(IUnknown* pUnkOuter,
|
|
DBID *pTableID, DBID *pIndexID,
|
|
REFIID riid,
|
|
ULONG cPropertySets, DBPROPSET rgPropertySets[],
|
|
IUnknown** ppRowset,
|
|
RowsetClass*& pRowsetObj)
|
|
{
|
|
HRESULT hr, hrProps = S_OK;
|
|
if (ppRowset != NULL)
|
|
*ppRowset = NULL;
|
|
if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
|
|
return DB_E_NOAGGREGATION;
|
|
CComPolyObject<RowsetClass>* pPolyObj;
|
|
if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
|
|
return hr;
|
|
// Ref the created COM object and Auto release it on failure
|
|
CComPtr<IUnknown> spUnk;
|
|
hr = pPolyObj->QueryInterface(&spUnk);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pPolyObj; // must hand delete as it is not ref'd
|
|
return hr;
|
|
}
|
|
// Get a pointer to the Rowset instance
|
|
pRowsetObj = &(pPolyObj->m_contained);
|
|
hr = pRowsetObj->FInit();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
hr = pRowsetObj->SetPropertiesArgChk(cPropertySets, rgPropertySets);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
const GUID* ppGuid[1];
|
|
ppGuid[0] = &DBPROPSET_ROWSET;
|
|
|
|
// Call SetProperties. The true in the last parameter indicates
|
|
// the special behavior that takes place on rowset creation (i.e.
|
|
// it succeeds as long as any of the properties were not marked
|
|
// as DBPROPS_REQUIRED.
|
|
|
|
hrProps = pRowsetObj->SetProperties(0, cPropertySets, rgPropertySets,
|
|
1, ppGuid, true);
|
|
if (FAILED(hrProps))
|
|
return hrProps;
|
|
|
|
pRowsetObj->SetSite(((SessionClass*)this)->GetUnknown());
|
|
|
|
hr = pRowsetObj->SetCommandText(pTableID, pIndexID);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
DBROWCOUNT cRowsAffected;
|
|
if (FAILED(hr = pRowsetObj->Execute(NULL, &cRowsAffected)))
|
|
return hr;
|
|
if (InlineIsEqualGUID(riid, IID_NULL))
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
else
|
|
{
|
|
if (ppRowset == NULL)
|
|
return (hrProps == DB_S_ERRORSOCCURRED) ? DB_E_ERRORSOCCURRED : hr;
|
|
|
|
hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
*ppRowset = NULL;
|
|
return hr;
|
|
}
|
|
return (hrProps == DB_S_ERRORSOCCURRED) ? hrProps : hr;
|
|
}
|
|
|
|
};
|
|
|
|
// IColumnsInfoImpl
|
|
template <class T>
|
|
class ATL_NO_VTABLE IColumnsInfoImpl :
|
|
public IColumnsInfo,
|
|
public CDBIDOps
|
|
{
|
|
public:
|
|
|
|
HRESULT CheckCommandText(IUnknown* pUnkThis)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CComPtr<ICommandText> spText;
|
|
if (SUCCEEDED(hr = pUnkThis->QueryInterface(IID_ICommandText, (void**)&spText)))
|
|
{
|
|
LPOLESTR szCommand;
|
|
hr = spText->GetCommandText(NULL, &szCommand);
|
|
if (SUCCEEDED(hr))
|
|
CoTaskMemFree(szCommand);
|
|
}
|
|
return hr;
|
|
}
|
|
OUT_OF_LINE HRESULT InternalGetColumnInfo(DBORDINAL *pcColumns, ATLCOLUMNINFO** ppInfo)
|
|
{
|
|
ATLASSERT(ppInfo != NULL);
|
|
T* pT = (T*) this;
|
|
if (pT->CheckCommandText(pT->GetUnknown()) == DB_E_NOCOMMAND)
|
|
return DB_E_NOCOMMAND;
|
|
*ppInfo = T::GetColumnInfo(pT, pcColumns);
|
|
return S_OK;
|
|
|
|
}
|
|
STDMETHOD(GetColumnInfo)(DBORDINAL *pcColumns,
|
|
DBCOLUMNINFO **prgInfo,
|
|
OLECHAR **ppStringsBuffer)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::GetColumnInfo\n");
|
|
if (pcColumns == NULL || prgInfo == NULL || ppStringsBuffer == NULL)
|
|
{
|
|
if (prgInfo != NULL)
|
|
*prgInfo = NULL;
|
|
if (ppStringsBuffer != NULL)
|
|
*ppStringsBuffer = NULL;
|
|
if (pcColumns != NULL)
|
|
*pcColumns = NULL;
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// NULL out pointers in case of an error
|
|
*prgInfo = NULL;
|
|
*ppStringsBuffer = NULL;
|
|
*pcColumns = 0;
|
|
|
|
ATLCOLUMNINFO* pInfo;
|
|
HRESULT hr = InternalGetColumnInfo(pcColumns, &pInfo);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
ATLASSERT(pInfo != NULL);
|
|
*prgInfo = (DBCOLUMNINFO*)CoTaskMemAlloc(*pcColumns * sizeof(DBCOLUMNINFO));
|
|
if (*prgInfo != NULL)
|
|
{
|
|
for (DBORDINAL iCol = 0, cwRequired = 0; iCol < *pcColumns; iCol++)
|
|
{
|
|
memcpy(&((*prgInfo)[iCol]), &pInfo[iCol], sizeof(DBCOLUMNINFO));
|
|
if (pInfo[iCol].pwszName)
|
|
{
|
|
cwRequired += wcslen(pInfo[iCol].pwszName) + 1;
|
|
}
|
|
}
|
|
*ppStringsBuffer = (OLECHAR*)CoTaskMemAlloc(cwRequired*sizeof(OLECHAR));
|
|
if (*ppStringsBuffer)
|
|
{
|
|
for (DBORDINAL iCol = 0, iOffset = 0; iCol < *pcColumns; iCol++)
|
|
{
|
|
if (pInfo[iCol].pwszName)
|
|
{
|
|
lstrcpyW(*ppStringsBuffer + iOffset, pInfo[iCol].pwszName);
|
|
iOffset += wcslen(*ppStringsBuffer + iOffset) + 1;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate string buffer\n"));
|
|
CoTaskMemFree(*prgInfo);
|
|
*prgInfo = NULL;
|
|
*pcColumns = 0;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ColumnInfo array\n"));
|
|
*prgInfo = NULL;
|
|
*pcColumns = 0;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
}
|
|
|
|
STDMETHOD(MapColumnIDs)(DBORDINAL cColumnIDs,
|
|
const DBID rgColumnIDs[],
|
|
DBORDINAL rgColumns[])
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IColumnsInfoImpl::MapColumnIDs\n");
|
|
USES_CONVERSION;
|
|
if ((cColumnIDs != 0 && rgColumnIDs == NULL) || rgColumns == NULL)
|
|
return E_INVALIDARG;
|
|
DBORDINAL cCols = 0;
|
|
DBORDINAL cColsInError = 0;
|
|
HRESULT hr = S_OK;
|
|
ATLCOLUMNINFO* pInfo;
|
|
for (DBORDINAL iColId = 0; iColId < cColumnIDs; iColId++)
|
|
{
|
|
hr = InternalGetColumnInfo(&cCols, &pInfo);
|
|
if (hr == DB_E_NOCOMMAND)
|
|
return hr;
|
|
ULONG iColMapCur = 0;
|
|
BOOL bDone = FALSE;
|
|
while(iColMapCur < cCols && !bDone)
|
|
{
|
|
hr = CompareDBIDs(&(pInfo[iColMapCur].columnid), &(rgColumnIDs[iColId]));
|
|
bDone = (hr == S_OK || FAILED(hr));
|
|
if (hr == S_OK)
|
|
rgColumns[iColId] = pInfo[iColMapCur].iOrdinal;
|
|
iColMapCur++;
|
|
}
|
|
if (!bDone || FAILED(hr))
|
|
{
|
|
rgColumns[iColId] = DB_INVALIDCOLUMN;
|
|
cColsInError++;
|
|
}
|
|
|
|
}
|
|
if (cColsInError > 0 && cColumnIDs == cColsInError)
|
|
return DB_E_ERRORSOCCURRED;
|
|
if (cColsInError > 0 && cColsInError < cColumnIDs)
|
|
return DB_S_ERRORSOCCURRED;
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
//IConvertTypeImpl
|
|
template <class T>
|
|
class ATL_NO_VTABLE IConvertTypeImpl : public IConvertType, public CConvertHelper
|
|
{
|
|
public:
|
|
HRESULT InternalCanConvert(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags,
|
|
bool bIsCommand, bool bHasParamaters, IObjectWithSite* pSite)
|
|
{
|
|
|
|
// Check to see if conversion types are invalid. Note, this is just a
|
|
// quick test as it would be difficult to check each available type
|
|
// (as new DBTYPE values can be added).
|
|
if ((wFromType & 0x8000) || (wToType & 0x8000))
|
|
return E_INVALIDARG;
|
|
|
|
// Determine if new 2.x flags are valid
|
|
if((dwConvertFlags & ~(DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_ISFIXEDLENGTH)) != DBCONVERTFLAGS_COLUMN
|
|
&& (dwConvertFlags & ~(DBCONVERTFLAGS_ISLONG | DBCONVERTFLAGS_ISFIXEDLENGTH)) != DBCONVERTFLAGS_PARAMETER )
|
|
return DB_E_BADCONVERTFLAG;
|
|
|
|
#ifdef _LATER
|
|
// If the convert flags are for DBCONVERTFLAGS_FROMVARIANT, check to see
|
|
// that the type is a variant type
|
|
if (dwConvertFlags == DBCONVERTFLAGS_FROMVARIANT)
|
|
{
|
|
if (wFromType != DBTYPE_VARIANT)
|
|
return DB_E_BADTYPE;
|
|
}
|
|
#endif // _LATER
|
|
|
|
// Note, if the convert flag is either ISLONG or ISFIXEDLENGTH, then we should
|
|
// make sure we are not dealing with an OLE DB 1.x provider. However, since
|
|
// we default to 2.x providers, we don't check this. If you, change the
|
|
// DBPROP_PROVIDEROLEDBVER property in the DATASOURCEINFO group, you need to
|
|
// check the property value and return a DB_E_BADCONVERTFLAG if it is a 1.x
|
|
// provider.
|
|
|
|
// Do we have ISLONG on a fixed length data type?
|
|
DBTYPE dbtype = wFromType & ~(DBTYPE_BYREF|DBTYPE_VECTOR|DBTYPE_ARRAY|DBTYPE_RESERVED);
|
|
if ((dwConvertFlags & DBCONVERTFLAGS_ISLONG) &&
|
|
(dbtype != DBTYPE_WSTR && dbtype != DBTYPE_STR && dbtype != DBTYPE_BYTES && dbtype != DBTYPE_VARNUMERIC))
|
|
return DB_E_BADCONVERTFLAG;
|
|
|
|
if (dwConvertFlags == DBCONVERTFLAGS_PARAMETER)
|
|
{
|
|
// In the case where we are a rowset and ask for a parameter
|
|
// conversion, return DB_E_BADCONVERTFLAG
|
|
if (!bIsCommand)
|
|
return DB_E_BADCONVERTFLAG;
|
|
|
|
// In the case where we are a command and ask for a parameter
|
|
// conversion and ICommandWithParameters is not supported, return
|
|
// S_FALSE. We just can't convert them.
|
|
if (!bHasParamaters)
|
|
return S_FALSE;
|
|
}
|
|
|
|
// If we deal with a command and the user asks for a conversion on a rowset
|
|
// the DBPROP_ROWSETCONVERSIONSONCOMMAND must be suppored and set to TRUE.
|
|
if (bIsCommand && dwConvertFlags == DBCONVERTFLAGS_COLUMN)
|
|
{
|
|
CDBPropIDSet set(DBPROPSET_DATASOURCEINFO);
|
|
set.AddPropertyID(DBPROP_ROWSETCONVERSIONSONCOMMAND);
|
|
DBPROPSET* pPropSet = NULL;
|
|
ULONG ulPropSet = 0;
|
|
//HRESULT hr1 = S_OK;
|
|
|
|
// Get a pointer into the session
|
|
CComPtr<IGetDataSource> spDataSource = NULL;
|
|
CComPtr<IDBProperties> spProps = NULL;
|
|
|
|
// if any of these calls fail, we're either unable to retrieve the
|
|
// property or it is unsupported. Since the property is only on
|
|
// the data source object, we use the IObjectWithSite interface to
|
|
// get the session object and then the GetDataSource method to get
|
|
// the data source object itself.
|
|
if (FAILED(pSite->GetSite(IID_IGetDataSource, (void**)&spDataSource)))
|
|
return DB_E_BADCONVERTFLAG;
|
|
if (FAILED(spDataSource->GetDataSource(IID_IDBProperties,
|
|
(IUnknown**)&spProps)))
|
|
return DB_E_BADCONVERTFLAG;
|
|
if (FAILED(spProps->GetProperties(1, &set, &ulPropSet, &pPropSet)))
|
|
return DB_E_BADCONVERTFLAG;
|
|
|
|
if (pPropSet != NULL)
|
|
{
|
|
CComVariant var = pPropSet->rgProperties[0].vValue;
|
|
CoTaskMemFree(pPropSet->rgProperties);
|
|
CoTaskMemFree(pPropSet);
|
|
|
|
if (var.boolVal == VARIANT_FALSE)
|
|
return DB_E_BADCONVERTFLAG;
|
|
}
|
|
}
|
|
HRESULT hr = E_FAIL;
|
|
if (m_spConvert != NULL)
|
|
{
|
|
hr = m_spConvert->CanConvert(wFromType, wToType);
|
|
}
|
|
return hr;
|
|
}
|
|
STDMETHOD(CanConvert)(DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IConvertTypeImpl::CanConvert\n");
|
|
T* pT = (T*)this;
|
|
return pT->InternalCanConvert(wFromType, wToType, dwConvertFlags, pT->m_bIsCommand, pT->m_bHasParamaters, pT);
|
|
}
|
|
};
|
|
|
|
template <class T, class PropClass = T>
|
|
class ATL_NO_VTABLE ICommandPropertiesImpl :
|
|
public ICommandProperties,
|
|
public CUtlProps<PropClass>
|
|
{
|
|
public:
|
|
typedef PropClass _PropClass;
|
|
|
|
STDMETHOD(GetProperties)(const ULONG cPropertyIDSets,
|
|
const DBPROPIDSET rgPropertyIDSets[],
|
|
ULONG *pcPropertySets,
|
|
DBPROPSET **prgPropertySets)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::GetProperties\n");
|
|
HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
|
|
const GUID* ppGuid[1];
|
|
ppGuid[0] = &DBPROPSET_ROWSET;
|
|
if(SUCCEEDED(hr))
|
|
hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
|
|
rgPropertyIDSets, pcPropertySets, prgPropertySets,
|
|
1, ppGuid);
|
|
return hr;
|
|
|
|
}
|
|
|
|
STDMETHOD(SetProperties)(ULONG cPropertySets,
|
|
DBPROPSET rgPropertySets[])
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandPropertiesImpl::SetProperties\n");
|
|
HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets);
|
|
const GUID* ppGuid[1];
|
|
ppGuid[0] = &DBPROPSET_ROWSET;
|
|
if(SUCCEEDED(hr))
|
|
hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets,
|
|
rgPropertySets, 1, ppGuid);
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
class CRunTimeFree
|
|
{
|
|
public:
|
|
|
|
static void Free(T* pData)
|
|
{
|
|
delete [] pData;
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
class CComFree
|
|
{
|
|
public:
|
|
|
|
static void Free(T* pData)
|
|
{
|
|
CoTaskMemFree(pData);
|
|
}
|
|
};
|
|
|
|
|
|
template <class T, class DeAllocator = CRunTimeFree < T > >
|
|
class CAutoMemRelease
|
|
{
|
|
public:
|
|
CAutoMemRelease()
|
|
{
|
|
m_pData = NULL;
|
|
}
|
|
|
|
CAutoMemRelease(T* pData)
|
|
{
|
|
m_pData = pData;
|
|
}
|
|
|
|
~CAutoMemRelease()
|
|
{
|
|
Attach(NULL);
|
|
}
|
|
|
|
void Attach(T* pData)
|
|
{
|
|
DeAllocator::Free(m_pData);
|
|
m_pData = pData;
|
|
}
|
|
|
|
T* Detach()
|
|
{
|
|
T* pTemp = m_pData;
|
|
m_pData = NULL;
|
|
return pTemp;
|
|
}
|
|
|
|
T* m_pData;
|
|
};
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE ICommandImpl : public ICommand
|
|
{
|
|
public:
|
|
ICommandImpl()
|
|
{
|
|
m_bIsExecuting = FALSE;
|
|
m_bCancelWhenExecuting = TRUE;
|
|
m_bCancel = FALSE;
|
|
}
|
|
HRESULT CancelExecution()
|
|
{
|
|
T* pT = (T*)this;
|
|
pT->Lock();
|
|
m_bCancel = TRUE;
|
|
pT->Unlock();
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(Cancel)()
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::Cancel\n");
|
|
HRESULT hr = S_OK;
|
|
T* pT = (T*)this;
|
|
|
|
if (m_bIsExecuting && m_bCancelWhenExecuting)
|
|
{
|
|
hr = pT->CancelExecution();
|
|
return hr;
|
|
}
|
|
if (m_bIsExecuting && !m_bCancelWhenExecuting)
|
|
hr = DB_E_CANTCANCEL;
|
|
return hr;
|
|
}
|
|
STDMETHOD(GetDBSession)(REFIID riid, IUnknown ** ppSession)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::GetDBSession\n");
|
|
T* pT = (T*)this;
|
|
ATLASSERT(pT->m_spUnkSite != NULL);
|
|
return pT->m_spUnkSite->QueryInterface(riid, (void**) ppSession);
|
|
}
|
|
|
|
template <class RowsetClass>
|
|
HRESULT CreateRowset(IUnknown* pUnkOuter, REFIID riid,
|
|
DBPARAMS * pParams, DBROWCOUNT * pcRowsAffected,
|
|
IUnknown** ppRowset,
|
|
RowsetClass*& pRowsetObj)
|
|
{
|
|
HRESULT hr;
|
|
USES_CONVERSION;
|
|
int iBind;
|
|
T* pT = (T*)this;
|
|
if (ppRowset != NULL)
|
|
*ppRowset = NULL;
|
|
if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
|
|
return DB_E_NOAGGREGATION;
|
|
CComPolyObject<RowsetClass>* pPolyObj;
|
|
if (FAILED(hr = CComPolyObject<RowsetClass>::CreateInstance(pUnkOuter, &pPolyObj)))
|
|
return hr;
|
|
// Ref the created COM object and Auto release it on failure
|
|
CComPtr<IUnknown> spUnk;
|
|
hr = pPolyObj->QueryInterface(&spUnk);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pPolyObj; // must hand delete as it is not ref'd
|
|
return hr;
|
|
}
|
|
// Get a pointer to the Rowset instance
|
|
pRowsetObj = &(pPolyObj->m_contained);
|
|
|
|
if (FAILED(hr = pRowsetObj->FInit(pT)))
|
|
return hr;
|
|
pRowsetObj->SetSite(pT->GetUnknown());
|
|
|
|
if (pT->m_strCommandText.Length() == 0)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandImpl::No command text specified.\n");
|
|
return DB_E_NOCOMMAND;
|
|
}
|
|
|
|
pRowsetObj->m_strCommandText = pT->m_strCommandText;
|
|
if (pRowsetObj->m_strCommandText == (BSTR)NULL)
|
|
return E_OUTOFMEMORY;
|
|
if (FAILED(hr = pRowsetObj->Execute(pParams, pcRowsAffected)))
|
|
return hr;
|
|
if (InlineIsEqualGUID(riid, IID_NULL) || ppRowset == NULL)
|
|
{
|
|
if (ppRowset != NULL)
|
|
*ppRowset = NULL;
|
|
return hr;
|
|
}
|
|
hr = pPolyObj->QueryInterface(riid, (void**)ppRowset);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
for (iBind = 0; iBind < pT->m_rgBindings.GetSize(); iBind++)
|
|
{
|
|
T::_BindType* pBind = NULL;
|
|
T::_BindType* pBindSrc = NULL;
|
|
ATLTRY(pBind = new T::_BindType);
|
|
if (pBind == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to allocate memory for new Binding\n");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
// auto cleanup on failure
|
|
CAutoMemRelease<T::_BindType> amr(pBind);
|
|
pBindSrc = pT->m_rgBindings.GetValueAt(iBind);
|
|
if (pBindSrc == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "The map appears to be corrupted, failing!!\n");
|
|
return E_FAIL;
|
|
}
|
|
if (!pRowsetObj->m_rgBindings.Add(pT->m_rgBindings.GetKeyAt(iBind), pBind))
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to add hAccessor to Map\n");
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if (pBindSrc->cBindings)
|
|
{
|
|
ATLTRY(pBind->pBindings = new DBBINDING[pBindSrc->cBindings])
|
|
if (pBind->pBindings == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Failed to Allocate dbbinding Array\n");
|
|
// We added it, must now remove on failure
|
|
pRowsetObj->m_rgBindings.Remove(pT->m_rgBindings.GetKeyAt(iBind));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pBind->pBindings = NULL; // NULL Accessor
|
|
}
|
|
|
|
pBind->dwAccessorFlags = pBindSrc->dwAccessorFlags;
|
|
pBind->cBindings = pBindSrc->cBindings;
|
|
pBind->dwRef = 1;
|
|
memcpy (pBind->pBindings, pBindSrc->pBindings, (pBindSrc->cBindings)*sizeof(DBBINDING));
|
|
pBind = amr.Detach();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
unsigned m_bIsExecuting:1;
|
|
unsigned m_bCancelWhenExecuting:1;
|
|
unsigned m_bCancel:1;
|
|
};
|
|
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE ICommandTextImpl : public ICommandImpl<T>
|
|
{
|
|
public:
|
|
STDMETHOD(GetCommandText)(GUID * /*pguidDialect*/,LPOLESTR * ppwszCommand)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText\n");
|
|
UINT cchCommandText;
|
|
HRESULT hr = E_FAIL;
|
|
if (ppwszCommand == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
if (m_strCommandText.m_str == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::GetCommandText Bad Command buffer\n");
|
|
return DB_E_NOCOMMAND;
|
|
}
|
|
cchCommandText = sizeof(OLECHAR) * (m_strCommandText.Length() + 1);
|
|
*ppwszCommand = (OLECHAR*)CoTaskMemAlloc(cchCommandText);
|
|
if (*ppwszCommand != NULL)
|
|
{
|
|
memcpy(*ppwszCommand, m_strCommandText.m_str, cchCommandText);
|
|
*(*ppwszCommand + m_strCommandText.Length()) = (OLECHAR)NULL;
|
|
return S_OK;
|
|
}
|
|
*ppwszCommand = NULL;
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(SetCommandText)(REFGUID /*rguidDialect*/,LPCOLESTR pwszCommand)
|
|
{
|
|
T* pT = (T*)this;
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ICommandTextImpl::SetCommandText\n");
|
|
pT->Lock();
|
|
m_strCommandText = pwszCommand;
|
|
pT->Unlock();
|
|
return S_OK;
|
|
}
|
|
|
|
CComBSTR m_strCommandText;
|
|
};
|
|
|
|
// ISessionPropertiesImpl
|
|
template <class T, class PropClass = T>
|
|
class ATL_NO_VTABLE ISessionPropertiesImpl :
|
|
public ISessionProperties,
|
|
public CUtlProps<PropClass>
|
|
{
|
|
public:
|
|
typedef PropClass _PropClass;
|
|
|
|
STDMETHOD(GetProperties)(ULONG cPropertyIDSets,
|
|
const DBPROPIDSET rgPropertyIDSets[],
|
|
ULONG *pcPropertySets,
|
|
DBPROPSET **prgPropertySets)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::GetProperties\n");
|
|
HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
|
|
const GUID* ppGuid[1];
|
|
ppGuid[0] = &DBPROPSET_SESSION;
|
|
|
|
if(SUCCEEDED(hr))
|
|
hr = CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
|
|
rgPropertyIDSets, pcPropertySets, prgPropertySets,
|
|
1, ppGuid);
|
|
return hr;
|
|
|
|
}
|
|
|
|
STDMETHOD(SetProperties)(ULONG cPropertySets,
|
|
DBPROPSET rgPropertySets[])
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "ISessionPropertiesImpl::SetProperties");
|
|
HRESULT hr = SetPropertiesArgChk(cPropertySets, rgPropertySets);
|
|
const GUID* ppGuid[1];
|
|
|
|
ppGuid[0] = &DBPROPSET_SESSION;
|
|
if(SUCCEEDED(hr))
|
|
hr = CUtlProps<PropClass>::SetProperties(0, cPropertySets, rgPropertySets,
|
|
1, ppGuid);
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
// Implementation Class
|
|
template <class BindType>
|
|
class ATL_NO_VTABLE IAccessorImplBase : public IAccessor
|
|
{
|
|
public:
|
|
|
|
STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags,
|
|
DBCOUNTITEM cBindings,
|
|
const DBBINDING rgBindings[],
|
|
DBLENGTH /*cbRowSize*/,
|
|
HACCESSOR *phAccessor,
|
|
DBBINDSTATUS rgStatus[])
|
|
{
|
|
if (!(dwAccessorFlags & DBACCESSOR_PARAMETERDATA) && !(dwAccessorFlags & DBACCESSOR_ROWDATA))
|
|
return DB_E_BADACCESSORFLAGS;
|
|
if (dwAccessorFlags == DBACCESSOR_INVALID)
|
|
return DB_E_BADACCESSORFLAGS;
|
|
if (dwAccessorFlags > 0x000F)
|
|
return DB_E_BADACCESSORFLAGS;
|
|
BindType *pBind = NULL;
|
|
ATLTRY(pBind = new BindType)
|
|
if (pBind == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("Failed to allocate ATL Binding struct\n"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if (cBindings)
|
|
{
|
|
ATLTRY(pBind->pBindings = new DBBINDING[cBindings])
|
|
if (pBind->pBindings == NULL)
|
|
{
|
|
delete pBind;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
pBind->pBindings = NULL; // NULL Accessor
|
|
|
|
pBind->dwAccessorFlags = dwAccessorFlags;
|
|
pBind->cBindings = cBindings;
|
|
pBind->dwRef = 1;
|
|
memcpy (pBind->pBindings, rgBindings, cBindings*sizeof(DBBINDING));
|
|
DBBINDSTATUS status = DBBINDSTATUS_OK;
|
|
memset (rgStatus, status, sizeof(DBBINDSTATUS)*cBindings);
|
|
*phAccessor = (ULONG_PTR)pBind;
|
|
return S_OK;
|
|
}
|
|
BOOL HasFlag(DBTYPE dbToCheck, DBTYPE dbCombo)
|
|
{
|
|
return ( (dbToCheck & dbCombo) == dbCombo );
|
|
}
|
|
HRESULT ValidateBindings(DBCOUNTITEM cBindings, const DBBINDING rgBindings[],
|
|
DBBINDSTATUS rgStatus[], bool bHasBookmarks)
|
|
{
|
|
HRESULT hr = S_OK;;
|
|
|
|
for (ULONG iBinding = 0; iBinding < cBindings; iBinding++)
|
|
{
|
|
const DBBINDING& rBindCur = rgBindings[iBinding];
|
|
if (rBindCur.iOrdinal == 0)
|
|
{
|
|
if (!m_bIsCommand && !bHasBookmarks)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL;
|
|
continue;
|
|
}
|
|
}
|
|
if (rBindCur.dwPart == 0) // nothing to bind to
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_ARRAY)))
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
if (HasFlag(rBindCur.wType, (DBTYPE_BYREF | DBTYPE_VECTOR)))
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
if (HasFlag(rBindCur.wType, (DBTYPE_VECTOR | DBTYPE_ARRAY)))
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
if (rBindCur.wType == DBTYPE_NULL || rBindCur.wType == DBTYPE_EMPTY)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
if (HasFlag(rBindCur.wType, DBTYPE_RESERVED))
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
// Search for DBTYPE_BYREF | DBTYPE_EMPTY
|
|
if ((rBindCur.wType & 0xBFFF) == 0)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
if ((rBindCur.wType & 0xBFFE) == 0)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED)
|
|
{
|
|
BOOL bIsPointerType = HasFlag(rBindCur.wType, DBTYPE_BYREF) ||
|
|
HasFlag(rBindCur.wType, DBTYPE_VECTOR) ||
|
|
HasFlag(rBindCur.wType, DBTYPE_ARRAY) ||
|
|
HasFlag(~(DBTYPE_BYREF) & rBindCur.wType, DBTYPE_BSTR);
|
|
if (!bIsPointerType)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
unsigned m_bIsCommand:1;
|
|
unsigned m_bHasParamaters:1;
|
|
unsigned m_bIsChangeable:1;
|
|
};
|
|
|
|
// IAccessorImpl
|
|
template <class T, class BindType = ATLBINDINGS, class BindingVector = CSimpleMap < INT_PTR, BindType* > >
|
|
class ATL_NO_VTABLE IAccessorImpl : public IAccessorImplBase<BindType>
|
|
{
|
|
public:
|
|
typedef BindType _BindType;
|
|
typedef BindingVector _BindingVector;
|
|
IAccessorImpl()
|
|
{
|
|
m_bIsCommand = FALSE;
|
|
m_bHasParamaters = FALSE;
|
|
m_bIsChangeable = FALSE;
|
|
}
|
|
OUT_OF_LINE HRESULT InternalFinalConstruct(IUnknown* pUnkThis)
|
|
{
|
|
CComQIPtr<ICommand> spCommand = pUnkThis;
|
|
if (spCommand != NULL)
|
|
{
|
|
m_bIsCommand = TRUE;
|
|
CComQIPtr<ICommandWithParameters> spCommandParams = pUnkThis;
|
|
m_bHasParamaters = spCommandParams != NULL;
|
|
}
|
|
else // its a Rowset
|
|
{
|
|
CComQIPtr<IRowsetChange> spRSChange = pUnkThis;
|
|
m_bIsChangeable = spRSChange != NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
HRESULT FinalConstruct()
|
|
{
|
|
T* pT = (T*)this;
|
|
return InternalFinalConstruct(pT->GetUnknown());
|
|
}
|
|
void FinalRelease()
|
|
{
|
|
#ifdef _DEBUG
|
|
if (m_rgBindings.GetSize())
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::~IAccessorImpl Bindings still in vector, removing\n");
|
|
#endif //_DEBUG
|
|
while (m_rgBindings.GetSize())
|
|
ReleaseAccessor((HACCESSOR)m_rgBindings.GetKeyAt(0), NULL);
|
|
}
|
|
STDMETHOD(AddRefAccessor)(HACCESSOR hAccessor,
|
|
DBREFCOUNT *pcRefCount)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::AddRefAccessor\n");
|
|
if (hAccessor == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("AddRefAccessor : Bad hAccessor\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
if (pcRefCount == NULL)
|
|
pcRefCount = (ULONG*)_alloca(sizeof(ULONG));
|
|
|
|
BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
|
|
*pcRefCount = T::_ThreadModel::Increment((LONG*)&pBind->dwRef);
|
|
return S_OK;
|
|
}
|
|
OUT_OF_LINE ATLCOLUMNINFO* ValidateHelper(DBORDINAL* pcCols, CComPtr<IDataConvert> & rspConvert)
|
|
{
|
|
T* pT = (T*)this;
|
|
rspConvert = pT->m_spConvert;
|
|
return pT->GetColumnInfo(pT, pcCols);
|
|
}
|
|
OUT_OF_LINE HRESULT ValidateBindingsFromMetaData(DBCOUNTITEM cBindings, const DBBINDING rgBindings[],
|
|
DBBINDSTATUS rgStatus[], bool bHasBookmarks)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DBORDINAL cCols;
|
|
CComPtr<IDataConvert> spConvert;
|
|
ATLCOLUMNINFO* pColInfo = ValidateHelper(&cCols, spConvert);
|
|
ATLASSERT(pColInfo != NULL);
|
|
for (ULONG iBinding = 0; iBinding < cBindings; iBinding++)
|
|
{
|
|
const DBBINDING& rBindCur = rgBindings[iBinding];
|
|
DBORDINAL iOrdAdjusted;
|
|
if (bHasBookmarks)
|
|
iOrdAdjusted = rBindCur.iOrdinal; // Bookmarks start with ordinal 0
|
|
else
|
|
iOrdAdjusted = rBindCur.iOrdinal - 1; // Non-bookmarks start w/ ordinal 1
|
|
if (rBindCur.iOrdinal > cCols)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADORDINAL;
|
|
continue;
|
|
}
|
|
|
|
// If a binding specifies provider owned memory, and specifies type
|
|
// X | BYREF, and the provider's copy is not X or X | BYREF, return
|
|
// DBBINDSTATUS_BADBINDINFO
|
|
if (rBindCur.dwMemOwner == DBMEMOWNER_PROVIDEROWNED)
|
|
{
|
|
if ((rBindCur.wType & DBTYPE_BYREF) != 0)
|
|
{
|
|
DBTYPE dbConsumerType = rBindCur.wType & 0xBFFF;
|
|
DBTYPE dbProviderType = pColInfo[iOrdAdjusted].wType & 0xBFFF;
|
|
|
|
if (dbConsumerType != dbProviderType)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_BADBINDINFO;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
ATLASSERT(spConvert != NULL);
|
|
HRESULT hrConvert = spConvert->CanConvert(pColInfo[iOrdAdjusted].wType, rBindCur.wType);
|
|
if (FAILED(hrConvert) || hrConvert == S_FALSE)
|
|
{
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
rgStatus[iBinding] = DBBINDSTATUS_UNSUPPORTEDCONVERSION;
|
|
continue;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
STDMETHOD(CreateAccessor)(DBACCESSORFLAGS dwAccessorFlags,
|
|
DBCOUNTITEM cBindings,
|
|
const DBBINDING rgBindings[],
|
|
DBLENGTH cbRowSize,
|
|
HACCESSOR *phAccessor,
|
|
DBBINDSTATUS rgStatus[])
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor\n");
|
|
T* pT = (T*)this;
|
|
T::ObjectLock cab(pT);
|
|
|
|
if (!phAccessor)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Inavlid NULL Parameter for HACCESSOR*\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
*phAccessor = NULL;
|
|
if (cBindings != 0 && rgBindings == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::CreateAccessor : Bad Binding array\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
if (dwAccessorFlags & DBACCESSOR_PASSBYREF)
|
|
{
|
|
CComVariant varByRef;
|
|
HRESULT hr = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BYREFACCESSORS, &varByRef);
|
|
if (FAILED(hr) || varByRef.boolVal == VARIANT_FALSE)
|
|
return DB_E_BYREFACCESSORNOTSUPPORTED;
|
|
}
|
|
if (!m_bHasParamaters)
|
|
{
|
|
if (dwAccessorFlags & DBACCESSOR_PARAMETERDATA)
|
|
return DB_E_BADACCESSORFLAGS;
|
|
}
|
|
if (m_bIsCommand || !m_bIsChangeable)
|
|
{
|
|
if (cBindings == 0) // No NULL Accessors on the command
|
|
return DB_E_NULLACCESSORNOTSUPPORTED;
|
|
}
|
|
|
|
if (rgStatus == NULL && cBindings) // Create a fake status array
|
|
rgStatus = (DBBINDSTATUS*)_alloca(cBindings*sizeof(DBBINDSTATUS));
|
|
|
|
// Validate the Binding passed
|
|
HRESULT hr;
|
|
bool bHasBookmarks = false;
|
|
CComVariant varBookmarks;
|
|
HRESULT hrLocal = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_BOOKMARKS, &varBookmarks);
|
|
bHasBookmarks = (hrLocal == S_OK && varBookmarks.boolVal == VARIANT_TRUE);
|
|
|
|
hr = ValidateBindings(cBindings, rgBindings, rgStatus, bHasBookmarks);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
if (!m_bIsCommand)
|
|
{
|
|
hr = ValidateBindingsFromMetaData(cBindings, rgBindings, rgStatus,
|
|
bHasBookmarks);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
hr = IAccessorImplBase<BindType>::CreateAccessor(dwAccessorFlags, cBindings,
|
|
rgBindings, cbRowSize, phAccessor,rgStatus);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ATLASSERT(*phAccessor != NULL);
|
|
BindType* pBind = (BindType*)*phAccessor;
|
|
hr = m_rgBindings.Add((HACCESSOR)pBind, pBind) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
|
|
}
|
|
|
|
STDMETHOD(GetBindings)(HACCESSOR hAccessor,
|
|
DBACCESSORFLAGS *pdwAccessorFlags,
|
|
DBCOUNTITEM *pcBindings,
|
|
DBBINDING **prgBindings)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IAccessorImpl::GetBindings");
|
|
|
|
// Zero output parameters in case of failure
|
|
if (pdwAccessorFlags != NULL)
|
|
*pdwAccessorFlags = NULL;
|
|
|
|
if (pcBindings != NULL)
|
|
*pcBindings = NULL;
|
|
|
|
if (prgBindings != NULL)
|
|
*prgBindings = NULL;
|
|
|
|
// Check if any of the out params are NULL pointers
|
|
if ((pdwAccessorFlags && pcBindings && prgBindings) == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
|
|
HRESULT hr = DB_E_BADACCESSORHANDLE;
|
|
if (pBind != NULL)
|
|
{
|
|
*pdwAccessorFlags = pBind->dwAccessorFlags;
|
|
*pcBindings = pBind->cBindings;
|
|
*prgBindings = (DBBINDING*)CoTaskMemAlloc(*pcBindings * sizeof(DBBINDING));
|
|
if (*prgBindings == NULL)
|
|
return E_OUTOFMEMORY;
|
|
memcpy(*prgBindings, pBind->pBindings, sizeof(DBBINDING) * (*pcBindings));
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(ReleaseAccessor)(HACCESSOR hAccessor,
|
|
DBREFCOUNT *pcRefCount)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("IAccessorImpl::ReleaseAccessor\n"));
|
|
BindType* pBind = m_rgBindings.Lookup((int)hAccessor);
|
|
if (pBind == NULL)
|
|
return DB_E_BADACCESSORHANDLE;
|
|
|
|
if (pcRefCount == NULL)
|
|
pcRefCount = (DBREFCOUNT*)_alloca(sizeof(DBREFCOUNT));
|
|
*pcRefCount = T::_ThreadModel::Decrement((LONG*)&pBind->dwRef);
|
|
if (!(*pcRefCount))
|
|
{
|
|
delete [] pBind->pBindings;
|
|
delete pBind;
|
|
return m_rgBindings.Remove((int)hAccessor) ? S_OK : DB_E_BADACCESSORHANDLE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
BindingVector m_rgBindings;
|
|
};
|
|
|
|
#define BEGIN_PROVIDER_COLUMN_MAP(theClass) \
|
|
typedef theClass _Class; \
|
|
template <class T> \
|
|
static ATLCOLUMNINFO* GetColumnInfo(T* pv, DBORDINAL* pcCols) \
|
|
{ \
|
|
pv; \
|
|
static ATLCOLUMNINFO _rgColumns [] = \
|
|
{
|
|
|
|
#define SIZEOF_MEMBER(memberOf, member) \
|
|
sizeof(((memberOf*)0)->member)
|
|
#define EXPANDGUID(guid) \
|
|
{ guid.Data1, guid.Data2, guid.Data3, \
|
|
{ guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] } }
|
|
|
|
#define PROVIDER_COLUMN_ENTRY_GN(name, ordinal, flags, colSize, dbtype, precision, scale, guid) \
|
|
{ (LPOLESTR)name, (ITypeInfo*)NULL, (ULONG)ordinal, (DBCOLUMNFLAGS)flags, (ULONG)colSize, (DBTYPE)dbtype, (BYTE)precision, (BYTE)scale, { EXPANDGUID(guid), (DWORD)0, (LPOLESTR) name}, 0},
|
|
|
|
#define PROVIDER_COLUMN_ENTRY(name, ordinal, member) \
|
|
{ \
|
|
(LPOLESTR)OLESTR(name), \
|
|
(ITypeInfo*)NULL, \
|
|
(ULONG)ordinal, \
|
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, \
|
|
(ULONG)sizeof(((_Class*)0)->member), \
|
|
_GetOleDBType(((_Class*)0)->member), \
|
|
(BYTE)0, \
|
|
(BYTE)0, \
|
|
{ \
|
|
EXPANDGUID(GUID_NULL), \
|
|
(DWORD)2, \
|
|
(LPOLESTR) name \
|
|
}, \
|
|
offsetof(_Class, member) \
|
|
},
|
|
|
|
#define PROVIDER_COLUMN_ENTRY_LENGTH(name, ordinal, size, member) \
|
|
{ \
|
|
(LPOLESTR)OLESTR(name), \
|
|
(ITypeInfo*)NULL, \
|
|
(ULONG)ordinal, \
|
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, \
|
|
(ULONG)size, \
|
|
_GetOleDBType(((_Class*)0)->member), \
|
|
(BYTE)0, \
|
|
(BYTE)0, \
|
|
{ \
|
|
EXPANDGUID(GUID_NULL), \
|
|
(DWORD)2, \
|
|
(LPOLESTR) name \
|
|
}, \
|
|
offsetof(_Class, member) \
|
|
},
|
|
|
|
#define PROVIDER_COLUMN_ENTRY_TYPE_LENGTH(name, ordinal, type, size, member) \
|
|
{ \
|
|
(LPOLESTR)OLESTR(name), \
|
|
(ITypeInfo*)NULL, \
|
|
(ULONG)ordinal, \
|
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, \
|
|
(ULONG)size, \
|
|
(DBTYPE)type, \
|
|
(BYTE)0, \
|
|
(BYTE)0, \
|
|
{ \
|
|
EXPANDGUID(GUID_NULL), \
|
|
(DWORD)2, \
|
|
(LPOLESTR) name \
|
|
}, \
|
|
offsetof(_Class, member) \
|
|
},
|
|
|
|
#define PROVIDER_COLUMN_ENTRY_FIXED(name, ordinal, dbtype, member) \
|
|
{ \
|
|
(LPOLESTR)OLESTR(name), \
|
|
(ITypeInfo*)NULL, \
|
|
(ULONG)ordinal, \
|
|
DBCOLUMNFLAGS_ISFIXEDLENGTH, \
|
|
(ULONG)sizeof(((_Class*)0)->member), \
|
|
(DBTYPE)dbtype, \
|
|
(BYTE)0, \
|
|
(BYTE)0, \
|
|
{ \
|
|
EXPANDGUID(GUID_NULL), \
|
|
(DWORD)2, \
|
|
(LPOLESTR) name \
|
|
}, \
|
|
offsetof(_Class, member) \
|
|
},
|
|
|
|
#define PROVIDER_COLUMN_ENTRY_STR(name, ordinal, member) \
|
|
{ \
|
|
(LPOLESTR)OLESTR(name), \
|
|
(ITypeInfo*)NULL, \
|
|
(ULONG)ordinal, \
|
|
0, \
|
|
(ULONG)sizeof(((_Class*)0)->member), \
|
|
DBTYPE_STR, \
|
|
(BYTE)0xFF, \
|
|
(BYTE)0xFF, \
|
|
{ \
|
|
EXPANDGUID(GUID_NULL), \
|
|
(DWORD)2, \
|
|
(LPOLESTR) name \
|
|
}, \
|
|
offsetof(_Class, member) \
|
|
},
|
|
|
|
#define PROVIDER_COLUMN_ENTRY_WSTR(name, ordinal, member) \
|
|
{ \
|
|
(LPOLESTR)OLESTR(name), \
|
|
(ITypeInfo*)NULL, \
|
|
(ULONG)ordinal, \
|
|
0, \
|
|
(ULONG)sizeof(((_Class*)0)->member), \
|
|
DBTYPE_WSTR, \
|
|
(BYTE)0xFF, \
|
|
(BYTE)0xFF, \
|
|
{ \
|
|
EXPANDGUID(GUID_NULL), \
|
|
(DWORD)2, \
|
|
(LPOLESTR) name \
|
|
}, \
|
|
offsetof(_Class, member) \
|
|
},
|
|
|
|
#define END_PROVIDER_COLUMN_MAP() \
|
|
}; *pcCols = sizeof(_rgColumns)/sizeof(ATLCOLUMNINFO); return _rgColumns;}
|
|
|
|
// Implementation Class
|
|
class CSimpleRow
|
|
{
|
|
public:
|
|
typedef DBROWCOUNT KeyType;
|
|
|
|
CSimpleRow(DBROWCOUNT iRowsetCur)
|
|
{
|
|
m_dwRef = 0;
|
|
m_iRowset = iRowsetCur;
|
|
}
|
|
~CSimpleRow()
|
|
{
|
|
}
|
|
DWORD AddRefRow() { return CComObjectThreadModel::Increment((LPLONG)&m_dwRef); }
|
|
DWORD ReleaseRow() { return CComObjectThreadModel::Decrement((LPLONG)&m_dwRef); }
|
|
|
|
HRESULT Compare(CSimpleRow* pRow)
|
|
{
|
|
ATLASSERT(pRow != NULL);
|
|
return (m_iRowset == pRow->m_iRowset) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
KeyType m_iRowset;
|
|
DWORD m_dwRef;
|
|
};
|
|
|
|
// IRowsetImpl
|
|
template <class T, class RowsetInterface,
|
|
class RowClass = CSimpleRow,
|
|
class MapClass = CSimpleMap < RowClass::KeyType, RowClass* > >
|
|
class ATL_NO_VTABLE IRowsetImpl : public RowsetInterface
|
|
{
|
|
public:
|
|
typedef RowClass _HRowClass;
|
|
IRowsetImpl()
|
|
{
|
|
m_iRowset = 0;
|
|
m_bCanScrollBack = false;
|
|
m_bCanFetchBack = false;
|
|
m_bReset = true;
|
|
}
|
|
~IRowsetImpl()
|
|
{
|
|
for (int i = 0; i < m_rgRowHandles.GetSize(); i++)
|
|
delete (m_rgRowHandles.GetValueAt(i));
|
|
}
|
|
HRESULT RefRows(DBCOUNTITEM cRows, const HROW rghRows[], ULONG rgRefCounts[],
|
|
DBROWSTATUS rgRowStatus[], BOOL bAdd)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n");
|
|
if (cRows == 0)
|
|
return S_OK;
|
|
if (rghRows == NULL)
|
|
return E_INVALIDARG;
|
|
T::ObjectLock cab((T*)this);
|
|
BOOL bSuccess1 = FALSE;
|
|
BOOL bFailed1 = FALSE;
|
|
DBROWSTATUS rs;
|
|
DWORD dwRef;
|
|
for (ULONG iRow = 0; iRow < cRows; iRow++)
|
|
{
|
|
HROW hRowCur = rghRows[iRow];
|
|
RowClass* pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRowCur);
|
|
if (pRow == NULL)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "Could not find HANDLE %x in list\n");
|
|
rs = DBROWSTATUS_E_INVALID;
|
|
dwRef = 0;
|
|
bFailed1 = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (bAdd)
|
|
dwRef = pRow->AddRefRow();
|
|
else
|
|
{
|
|
dwRef = pRow->ReleaseRow();
|
|
if (dwRef == 0)
|
|
{
|
|
delete pRow;
|
|
m_rgRowHandles.Remove((RowClass::KeyType)hRowCur);
|
|
}
|
|
}
|
|
bSuccess1 = TRUE;
|
|
rs = DBROWSTATUS_S_OK;
|
|
}
|
|
if (rgRefCounts)
|
|
rgRefCounts[iRow] = dwRef;
|
|
if (rgRowStatus != NULL)
|
|
rgRowStatus[iRow] = rs;
|
|
}
|
|
if (!bSuccess1 && !bFailed1)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RefRows Unexpected state\n");
|
|
return E_FAIL;
|
|
}
|
|
HRESULT hr = S_OK;
|
|
if (bSuccess1 && bFailed1)
|
|
hr = DB_S_ERRORSOCCURRED;
|
|
if (!bSuccess1 && bFailed1)
|
|
hr = DB_E_ERRORSOCCURRED;
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(AddRefRows)(DBCOUNTITEM cRows,
|
|
const HROW rghRows[],
|
|
DBREFCOUNT rgRefCounts[],
|
|
DBROWSTATUS rgRowStatus[])
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::AddRefRows\n");
|
|
if (cRows == 0)
|
|
return S_OK;
|
|
return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, TRUE);
|
|
}
|
|
virtual DBSTATUS GetDBStatus(RowClass* , ATLCOLUMNINFO*)
|
|
{
|
|
return DBSTATUS_S_OK;
|
|
}
|
|
OUT_OF_LINE HRESULT GetDataHelper(HACCESSOR hAccessor,
|
|
ATLCOLUMNINFO*& rpInfo,
|
|
void** ppBinding,
|
|
void*& rpSrcData,
|
|
DBORDINAL& rcCols,
|
|
CComPtr<IDataConvert>& rspConvert,
|
|
RowClass* pRow)
|
|
{
|
|
ATLASSERT(ppBinding != NULL);
|
|
T* pT = (T*) this;
|
|
*ppBinding = (void*)pT->m_rgBindings.Lookup((int)hAccessor);
|
|
if (*ppBinding == NULL)
|
|
return DB_E_BADACCESSORHANDLE;
|
|
rpSrcData = (void*)&(pT->m_rgRowData[(int)(INT_PTR)(pRow->m_iRowset)]);
|
|
rpInfo = T::GetColumnInfo((T*)this, &rcCols);
|
|
rspConvert = pT->m_spConvert;
|
|
return S_OK;
|
|
|
|
}
|
|
STDMETHOD(GetData)(HROW hRow,
|
|
HACCESSOR hAccessor,
|
|
void *pDstData)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetData\n");
|
|
if (pDstData == NULL)
|
|
return E_INVALIDARG;
|
|
HRESULT hr = S_OK;
|
|
RowClass* pRow = (RowClass*)hRow;
|
|
if (hRow == NULL || (pRow = m_rgRowHandles.Lookup((RowClass::KeyType)hRow)) == NULL)
|
|
return DB_E_BADROWHANDLE;
|
|
T::_BindType* pBinding;
|
|
void* pSrcData;
|
|
DBORDINAL cCols;
|
|
ATLCOLUMNINFO* pColInfo;
|
|
CComPtr<IDataConvert> spConvert;
|
|
hr = GetDataHelper(hAccessor, pColInfo, (void**)&pBinding, pSrcData, cCols, spConvert, pRow);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
for (ULONG iBind =0; iBind < pBinding->cBindings; iBind++)
|
|
{
|
|
DBBINDING* pBindCur = &(pBinding->pBindings[iBind]);
|
|
for (ULONG iColInfo = 0;
|
|
iColInfo < cCols && pBindCur->iOrdinal != pColInfo[iColInfo].iOrdinal;
|
|
iColInfo++);
|
|
if (iColInfo == cCols)
|
|
return DB_E_BADORDINAL;
|
|
ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
|
|
// Ordinal found at iColInfo
|
|
BOOL bProvOwn = pBindCur->dwMemOwner == DBMEMOWNER_PROVIDEROWNED;
|
|
bProvOwn;
|
|
DBSTATUS dbStat = GetDBStatus(pRow, pColCur);
|
|
|
|
// If the provider's field is NULL, we can optimize this situation,
|
|
// set the fields to 0 and continue.
|
|
if (dbStat == DBSTATUS_S_ISNULL)
|
|
{
|
|
if (pBindCur->dwPart & DBPART_STATUS)
|
|
*((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat;
|
|
|
|
if (pBindCur->dwPart & DBPART_LENGTH)
|
|
*((ULONG*)((BYTE*)(pDstData) + pBindCur->obLength)) = 0;
|
|
|
|
if (pBindCur->dwPart & DBPART_VALUE)
|
|
*((BYTE*)(pDstData) + pBindCur->obValue) = NULL;
|
|
continue;
|
|
}
|
|
DBLENGTH cbDst = pBindCur->cbMaxLen;
|
|
DBLENGTH cbCol;
|
|
BYTE* pSrcTemp;
|
|
|
|
if (bProvOwn && pColCur->wType == pBindCur->wType)
|
|
{
|
|
pSrcTemp = ((BYTE*)(pSrcData) + pColCur->cbOffset);
|
|
}
|
|
else
|
|
{
|
|
BYTE* pDstTemp = (BYTE*)pDstData + pBindCur->obValue;
|
|
switch (pColCur->wType)
|
|
{
|
|
case DBTYPE_STR:
|
|
cbCol = lstrlenA((LPSTR)(((BYTE*)pSrcData) + pColCur->cbOffset));
|
|
break;
|
|
case DBTYPE_WSTR:
|
|
case DBTYPE_BSTR:
|
|
cbCol = lstrlenW((LPWSTR)(((BYTE*)pSrcData) + pColCur->cbOffset)) * sizeof(WCHAR);
|
|
break;
|
|
default:
|
|
cbCol = pColCur->ulColumnSize;
|
|
break;
|
|
}
|
|
if (pBindCur->dwPart & DBPART_VALUE)
|
|
{
|
|
hr = spConvert->DataConvert(pColCur->wType, pBindCur->wType,
|
|
cbCol, &cbDst, (BYTE*)(pSrcData) + pColCur->cbOffset,
|
|
pDstTemp, pBindCur->cbMaxLen, dbStat, &dbStat,
|
|
pBindCur->bPrecision, pBindCur->bScale,0);
|
|
}
|
|
}
|
|
if (pBindCur->dwPart & DBPART_LENGTH)
|
|
*((DBLENGTH*)((BYTE*)(pDstData) + pBindCur->obLength)) = cbDst;
|
|
if (pBindCur->dwPart & DBPART_STATUS)
|
|
*((DBSTATUS*)((BYTE*)(pDstData) + pBindCur->obStatus)) = dbStat;
|
|
if (FAILED(hr))
|
|
return hr;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CreateRow(DBROWOFFSET lRowsOffset, DBCOUNTITEM& cRowsObtained, HROW* rgRows)
|
|
{
|
|
RowClass* pRow = NULL;
|
|
ATLASSERT(lRowsOffset >= 0);
|
|
RowClass::KeyType key = lRowsOffset+1;
|
|
ATLASSERT(key > 0);
|
|
pRow = m_rgRowHandles.Lookup(key);
|
|
if (pRow == NULL)
|
|
{
|
|
ATLTRY(pRow = new RowClass(lRowsOffset))
|
|
if (pRow == NULL)
|
|
return E_OUTOFMEMORY;
|
|
if (!m_rgRowHandles.Add(key, pRow))
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
pRow->AddRefRow();
|
|
m_bReset = false;
|
|
rgRows[cRowsObtained++] = (HROW)key;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(GetNextRows)(HCHAPTER /*hReserved*/,
|
|
DBROWOFFSET lRowsOffset,
|
|
DBROWCOUNT cRows,
|
|
DBCOUNTITEM *pcRowsObtained,
|
|
HROW **prghRows)
|
|
{
|
|
DBROWOFFSET lTmpRows = lRowsOffset;
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::GetNextRows\n");
|
|
if (pcRowsObtained != NULL)
|
|
*pcRowsObtained = 0;
|
|
if (prghRows == NULL || pcRowsObtained == NULL)
|
|
return E_INVALIDARG;
|
|
if (cRows == 0)
|
|
return S_OK;
|
|
HRESULT hr = S_OK;
|
|
T* pT = (T*) this;
|
|
T::ObjectLock cab(pT);
|
|
if (lRowsOffset < 0 && !m_bCanScrollBack)
|
|
return DB_E_CANTSCROLLBACKWARDS;
|
|
if (cRows < 0 && !m_bCanFetchBack)
|
|
return DB_E_CANTFETCHBACKWARDS;
|
|
|
|
// Calculate # of rows in set and the base fetch position. If the rowset
|
|
// is at its head position, then lRowOffset < 0 means moving from the BACK
|
|
// of the rowset and not the front.
|
|
DBROWCOUNT cRowsInSet = pT->m_rgRowData.GetSize();
|
|
if (((lRowsOffset == LONG_MIN) && (cRowsInSet != LONG_MIN))
|
|
|| (abs((int)(INT_PTR)lRowsOffset)) > cRowsInSet ||
|
|
(abs((int)(INT_PTR)lRowsOffset) == cRowsInSet && lRowsOffset < 0 && cRows < 0) ||
|
|
(abs((int)(INT_PTR)lRowsOffset) == cRowsInSet && lRowsOffset > 0 && cRows > 0))
|
|
return DB_S_ENDOFROWSET;
|
|
|
|
// In the case where the user is moving backwards after moving forwards,
|
|
// we do not wrap around to the end of the rowset.
|
|
if ((m_iRowset == 0 && !m_bReset && cRows < 0) ||
|
|
(((LONG)m_iRowset + lRowsOffset) > cRowsInSet) ||
|
|
(m_iRowset == (DWORD)cRowsInSet && lRowsOffset >= 0 && cRows > 0))
|
|
return DB_S_ENDOFROWSET;
|
|
|
|
// Note, if m_bReset, m_iRowset must be 0
|
|
if (lRowsOffset < 0 && m_bReset)
|
|
{
|
|
ATLASSERT(m_iRowset == 0);
|
|
m_iRowset = cRowsInSet;
|
|
}
|
|
|
|
int iStepSize = cRows >= 0 ? 1 : -1;
|
|
|
|
// If cRows == LONG_MIN, we can't use ABS on it. Therefore, we reset it
|
|
// to a value just greater than cRowsInSet
|
|
if (cRows == LONG_MIN && cRowsInSet != LONG_MIN)
|
|
cRows = cRowsInSet + 2; // set the value to something we can deal with
|
|
else
|
|
cRows = abs((int)(INT_PTR)cRows);
|
|
|
|
if (iStepSize < 0 && m_iRowset == 0 && m_bReset && lRowsOffset <= 0)
|
|
m_iRowset = cRowsInSet;
|
|
|
|
lRowsOffset += m_iRowset;
|
|
|
|
*pcRowsObtained = 0;
|
|
CAutoMemRelease<HROW, CComFree< HROW > > amr;
|
|
if (*prghRows == NULL)
|
|
{
|
|
DBROWCOUNT cHandlesToAlloc = (cRows > cRowsInSet) ? cRowsInSet : cRows;
|
|
if (iStepSize == 1 && (cRowsInSet - lRowsOffset) < cHandlesToAlloc)
|
|
cHandlesToAlloc = cRowsInSet - lRowsOffset;
|
|
if (iStepSize == -1 && lRowsOffset < cHandlesToAlloc)
|
|
cHandlesToAlloc = lRowsOffset;
|
|
*prghRows = (HROW*)CoTaskMemAlloc((cHandlesToAlloc) * sizeof(HROW*));
|
|
amr.Attach(*prghRows);
|
|
}
|
|
if (*prghRows == NULL)
|
|
return E_OUTOFMEMORY;
|
|
while ((lRowsOffset >= 0 && cRows != 0) &&
|
|
((lRowsOffset < cRowsInSet) || (lRowsOffset <= cRowsInSet && iStepSize < 0)))
|
|
{
|
|
// cRows > cRowsInSet && iStepSize < 0
|
|
if (lRowsOffset == 0 && cRows > 0 && iStepSize < 0)
|
|
break;
|
|
|
|
// in the case where we have iStepSize < 0, move the row back
|
|
// further because we want the previous row
|
|
DBROWOFFSET lRow = lRowsOffset;
|
|
if ((lRowsOffset == 0) && (lTmpRows == 0) && (iStepSize < 0))
|
|
lRow = cRowsInSet;
|
|
|
|
if (iStepSize < 0)
|
|
lRow += iStepSize;
|
|
|
|
hr = pT->CreateRow(lRow, *pcRowsObtained, *prghRows);
|
|
if (FAILED(hr))
|
|
{
|
|
RefRows(*pcRowsObtained, *prghRows, NULL, NULL, FALSE);
|
|
for (ULONG iRowDel = 0; iRowDel < *pcRowsObtained; iRowDel++)
|
|
*prghRows[iRowDel] = NULL;
|
|
*pcRowsObtained = 0;
|
|
return hr;
|
|
}
|
|
cRows--;
|
|
lRowsOffset += iStepSize;
|
|
}
|
|
|
|
if ((lRowsOffset >= cRowsInSet && cRows) || (lRowsOffset < 0 && cRows) ||
|
|
(lRowsOffset == 0 && cRows > 0 && iStepSize < 0))
|
|
hr = DB_S_ENDOFROWSET;
|
|
m_iRowset = lRowsOffset;
|
|
if (SUCCEEDED(hr))
|
|
amr.Detach();
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(ReleaseRows)(DBCOUNTITEM cRows,
|
|
const HROW rghRows[],
|
|
DBROWOPTIONS rgRowOptions[],
|
|
DBREFCOUNT rgRefCounts[],
|
|
DBROWSTATUS rgRowStatus[])
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::ReleaseRows\n");
|
|
if (cRows == 0)
|
|
return S_OK;
|
|
rgRowOptions;
|
|
return RefRows(cRows, rghRows, rgRefCounts, rgRowStatus, FALSE);
|
|
}
|
|
|
|
STDMETHOD(RestartPosition)(HCHAPTER /*hReserved*/)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetImpl::RestartPosition\n");
|
|
m_iRowset = 0;
|
|
m_bReset = true;
|
|
return S_OK;
|
|
}
|
|
|
|
MapClass m_rgRowHandles;
|
|
DBCOUNTITEM m_iRowset; // cursor
|
|
unsigned m_bCanScrollBack:1;
|
|
unsigned m_bCanFetchBack:1;
|
|
unsigned m_bReset:1;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// IRowsetIdentityImpl
|
|
template <class T, class RowClass = CSimpleRow>
|
|
class ATL_NO_VTABLE IRowsetIdentityImpl : public IRowsetIdentity
|
|
{
|
|
public:
|
|
STDMETHOD(IsSameRow)(HROW hThisRow, HROW hThatRow)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, _T("IRowsetIdentityImpl::IsSameRow"));
|
|
T* pT = (T*)this;
|
|
|
|
// Validate row handles
|
|
RowClass* pRow1 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThisRow);
|
|
RowClass* pRow2 = pT->m_rgRowHandles.Lookup((RowClass::KeyType)hThatRow);
|
|
|
|
if (pRow1 == NULL || pRow2 == NULL)
|
|
return DB_E_BADROWHANDLE;
|
|
|
|
return pRow1->Compare(pRow2);
|
|
};
|
|
};
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE IInternalConnectionImpl : public IInternalConnection
|
|
{
|
|
public:
|
|
STDMETHOD(AddConnection)()
|
|
{
|
|
T* pT = (T*)this;
|
|
T::_ThreadModel::Increment(&pT->m_cSessionsOpen);
|
|
return S_OK;
|
|
}
|
|
STDMETHOD(ReleaseConnection)()
|
|
{
|
|
T* pT = (T*)this;
|
|
T::_ThreadModel::Decrement(&pT->m_cSessionsOpen);
|
|
return S_OK;
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE IObjectWithSiteSessionImpl : public IObjectWithSiteImpl< T >
|
|
{
|
|
public:
|
|
|
|
~IObjectWithSiteSessionImpl()
|
|
{
|
|
CComPtr<IInternalConnection> pConn;
|
|
if (m_spUnkSite != NULL)
|
|
{
|
|
if (SUCCEEDED(m_spUnkSite->QueryInterface(IID_IInternalConnection, (void**)&pConn)))
|
|
pConn->ReleaseConnection();
|
|
}
|
|
}
|
|
STDMETHOD(SetSite)(IUnknown* pCreator)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
T* pT = (T*)this;
|
|
pT->Lock();
|
|
m_spUnkSite = pCreator;
|
|
pT->Unlock();
|
|
CComPtr<IInternalConnection> pConn;
|
|
if (pCreator != NULL)
|
|
{
|
|
hr = pCreator->QueryInterface(IID_IInternalConnection, (void**)&pConn);
|
|
if (SUCCEEDED(hr))
|
|
hr = pConn->AddConnection();
|
|
}
|
|
return hr;
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE IRowsetCreatorImpl : public IObjectWithSiteImpl< T >
|
|
{
|
|
public:
|
|
|
|
STDMETHOD(SetSite)(IUnknown* pCreator)
|
|
{
|
|
T* pT = (T*)this;
|
|
HRESULT hr = S_OK;
|
|
pT->Lock();
|
|
m_spUnkSite = pCreator;
|
|
pT->Unlock();
|
|
CComVariant varPropScroll, varPropFetch;
|
|
HRESULT hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANSCROLLBACKWARDS, &varPropScroll);
|
|
if (SUCCEEDED(hrProps))
|
|
pT->m_bCanScrollBack = varPropScroll.boolVal == VARIANT_TRUE;
|
|
hrProps = pT->GetPropValue(&DBPROPSET_ROWSET, DBPROP_CANFETCHBACKWARDS, &varPropFetch);
|
|
if (SUCCEEDED(hrProps))
|
|
pT->m_bCanFetchBack = (varPropFetch.boolVal == VARIANT_TRUE);
|
|
return hr;
|
|
}
|
|
|
|
};
|
|
|
|
// IRowsetInfoImpl
|
|
template <class T, class PropClass = T>
|
|
class ATL_NO_VTABLE IRowsetInfoImpl :
|
|
public IRowsetInfo,
|
|
public CUtlProps<PropClass>
|
|
{
|
|
public:
|
|
static UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, UPROPSET* pSet = NULL, GUID* pguidSet = (GUID*)&(GUID_NULL))
|
|
{
|
|
return PropClass::_GetPropSet(pNumPropSets, pcElemPerSupported, pSet, pguidSet);
|
|
}
|
|
STDMETHOD(GetProperties)(const ULONG cPropertyIDSets,
|
|
const DBPROPIDSET rgPropertyIDSets[],
|
|
ULONG *pcPropertySets,
|
|
DBPROPSET **prgPropertySets)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetProperties\n");
|
|
HRESULT hr = GetPropertiesArgChk(cPropertyIDSets, rgPropertyIDSets, pcPropertySets, prgPropertySets);
|
|
const GUID* ppGuid[1];
|
|
ppGuid[0] = &DBPROPSET_ROWSET;
|
|
if(SUCCEEDED(hr))
|
|
return CUtlProps<PropClass>::GetProperties(cPropertyIDSets,
|
|
rgPropertyIDSets, pcPropertySets, prgPropertySets,
|
|
1, ppGuid);
|
|
else
|
|
return hr;
|
|
}
|
|
|
|
OUT_OF_LINE ATLCOLUMNINFO* InternalGetColumnInfo(DBORDINAL* pcCols)
|
|
{
|
|
return T::GetColumnInfo((T*)this, pcCols);
|
|
}
|
|
|
|
STDMETHOD(GetReferencedRowset)(DBORDINAL iOrdinal,
|
|
REFIID riid,
|
|
IUnknown **ppReferencedRowset)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset\n");
|
|
DBORDINAL cCols=0;
|
|
|
|
// Check Arguments
|
|
if( ppReferencedRowset == NULL )
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetReferencedRowset : Error NULL IUnk output Param\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
*ppReferencedRowset = NULL;
|
|
|
|
// Check to see if column in question is a bookmark
|
|
ATLCOLUMNINFO* pColInfo = InternalGetColumnInfo(&cCols);
|
|
|
|
for (ULONG iColInfo = 0;
|
|
iColInfo < cCols && iOrdinal != pColInfo[iColInfo].iOrdinal;
|
|
iColInfo++);
|
|
if (iColInfo == cCols)
|
|
return DB_E_BADORDINAL;
|
|
ATLCOLUMNINFO* pColCur = &(pColInfo[iColInfo]);
|
|
|
|
if ((pColCur->dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) == 0)
|
|
return DB_E_NOTAREFERENCECOLUMN;
|
|
|
|
// Query for requested interface
|
|
return QueryInterface(riid, (void**)ppReferencedRowset);
|
|
}
|
|
|
|
STDMETHOD(GetSpecification)(REFIID riid,
|
|
IUnknown **ppSpecification)
|
|
{
|
|
ATLTRACE2(atlTraceDBProvider, 0, "IRowsetInfoImpl::GetSpecification\n");
|
|
if (ppSpecification == NULL)
|
|
return E_INVALIDARG;
|
|
T* pT = (T*) this;
|
|
T::ObjectLock cab(pT);
|
|
ATLASSERT(pT->m_spUnkSite != NULL);
|
|
return pT->m_spUnkSite->QueryInterface(riid, (void**)ppSpecification);
|
|
}
|
|
};
|
|
|
|
|
|
template <class T, class Storage, class CreatorClass,
|
|
class ArrayType = CSimpleArray<Storage>,
|
|
class RowClass = CSimpleRow,
|
|
class RowsetInterface = IRowsetImpl < T, IRowset, RowClass> >
|
|
class CRowsetImpl :
|
|
public CComObjectRootEx<CreatorClass::_ThreadModel>,
|
|
public IAccessorImpl<T>,
|
|
public IRowsetIdentityImpl<T, RowClass>,
|
|
public IRowsetCreatorImpl<T>,
|
|
public IRowsetInfoImpl<T, CreatorClass::_PropClass>,
|
|
public IColumnsInfoImpl<T>,
|
|
public IConvertTypeImpl<T>,
|
|
public RowsetInterface
|
|
{
|
|
public:
|
|
|
|
typedef CreatorClass _RowsetCreatorClass;
|
|
typedef ArrayType _RowsetArrayType;
|
|
typedef CRowsetImpl< T, Storage, CreatorClass, ArrayType, RowClass, RowsetInterface> _RowsetBaseClass;
|
|
|
|
BEGIN_COM_MAP(CRowsetImpl)
|
|
COM_INTERFACE_ENTRY(IAccessor)
|
|
COM_INTERFACE_ENTRY(IObjectWithSite)
|
|
COM_INTERFACE_ENTRY(IRowsetInfo)
|
|
COM_INTERFACE_ENTRY(IColumnsInfo)
|
|
COM_INTERFACE_ENTRY(IConvertType)
|
|
COM_INTERFACE_ENTRY(IRowsetIdentity)
|
|
COM_INTERFACE_ENTRY(IRowset)
|
|
END_COM_MAP()
|
|
|
|
HRESULT FinalConstruct()
|
|
{
|
|
HRESULT hr = IAccessorImpl<T>::FinalConstruct();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
return CConvertHelper::FinalConstruct();
|
|
}
|
|
|
|
HRESULT NameFromDBID(DBID* pDBID, CComBSTR& bstr, bool bIndex)
|
|
{
|
|
|
|
if (pDBID->uName.pwszName != NULL)
|
|
{
|
|
bstr = pDBID->uName.pwszName;
|
|
if (m_strCommandText == (BSTR)NULL)
|
|
return E_OUTOFMEMORY;
|
|
return S_OK;
|
|
}
|
|
|
|
return (bIndex) ? DB_E_NOINDEX : DB_E_NOTABLE;
|
|
}
|
|
|
|
HRESULT GetCommandFromID(DBID* pTableID, DBID* pIndexID)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
|
|
if (pTableID == NULL && pIndexID == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
if (pTableID != NULL && pTableID->eKind == DBKIND_NAME)
|
|
{
|
|
hr = NameFromDBID(pTableID, m_strCommandText, true);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
if (pIndexID != NULL)
|
|
{
|
|
if (pIndexID->eKind == DBKIND_NAME)
|
|
{
|
|
hr = NameFromDBID(pIndexID, m_strIndexText, false);
|
|
if (FAILED(hr))
|
|
{
|
|
m_strCommandText.Empty();
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_strCommandText.Empty();
|
|
return DB_E_NOINDEX;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
if (pIndexID != NULL && pIndexID->eKind == DBKIND_NAME)
|
|
return NameFromDBID(pIndexID, m_strIndexText, false);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT ValidateCommandID(DBID* pTableID, DBID* pIndexID)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (pTableID != NULL)
|
|
{
|
|
hr = CUtlProps<T>::IsValidDBID(pTableID);
|
|
|
|
if (hr != S_OK)
|
|
return hr;
|
|
|
|
// Check for a NULL TABLE ID (where its a valid pointer but NULL)
|
|
if ((pTableID->eKind == DBKIND_GUID_NAME ||
|
|
pTableID->eKind == DBKIND_NAME ||
|
|
pTableID->eKind == DBKIND_PGUID_NAME)
|
|
&& pTableID->uName.pwszName == NULL)
|
|
return DB_E_NOTABLE;
|
|
}
|
|
|
|
if (pIndexID != NULL)
|
|
hr = CUtlProps<T>::IsValidDBID(pIndexID);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT SetCommandText(DBID* pTableID, DBID* pIndexID)
|
|
{
|
|
T* pT = (T*)this;
|
|
HRESULT hr = pT->ValidateCommandID(pTableID, pIndexID);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
hr = pT->GetCommandFromID(pTableID, pIndexID);
|
|
return hr;
|
|
}
|
|
void FinalRelease()
|
|
{
|
|
m_rgRowData.RemoveAll();
|
|
}
|
|
|
|
static ATLCOLUMNINFO* GetColumnInfo(T* pv, DBORDINAL* pcCols)
|
|
{
|
|
return Storage::GetColumnInfo(pv,pcCols);
|
|
}
|
|
|
|
|
|
CComBSTR m_strCommandText;
|
|
CComBSTR m_strIndexText;
|
|
ArrayType m_rgRowData;
|
|
};
|
|
|
|
class CTABLESRow
|
|
{
|
|
public:
|
|
|
|
WCHAR m_szCatalog[129];
|
|
WCHAR m_szSchema[129];
|
|
WCHAR m_szTable[129];
|
|
WCHAR m_szType[129];
|
|
WCHAR m_szDesc[129];
|
|
GUID m_guid;
|
|
ULONG m_ulPropID;
|
|
|
|
CTABLESRow()
|
|
{
|
|
m_szCatalog[0] = NULL;
|
|
m_szSchema[0] = NULL;
|
|
m_szTable[0] = NULL;
|
|
m_szType[0] = NULL;
|
|
m_szDesc[0] = NULL;
|
|
m_guid = GUID_NULL;
|
|
m_ulPropID = 0;
|
|
}
|
|
|
|
BEGIN_PROVIDER_COLUMN_MAP(CTABLESRow)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szCatalog)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szSchema)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTable)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_TYPE", 4, m_szType)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_GUID", 5, m_guid)
|
|
PROVIDER_COLUMN_ENTRY("DESCRIPTION", 6, m_szDesc)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_PROPID", 7, m_ulPropID)
|
|
END_PROVIDER_COLUMN_MAP()
|
|
|
|
};
|
|
|
|
|
|
class CCOLUMNSRow
|
|
{
|
|
public:
|
|
|
|
WCHAR m_szTableCatalog[129];
|
|
WCHAR m_szTableSchema[129];
|
|
WCHAR m_szTableName[129];
|
|
WCHAR m_szColumnName[129];
|
|
GUID m_guidColumn;
|
|
ULONG m_ulColumnPropID;
|
|
DBORDINAL m_ulOrdinalPosition;
|
|
VARIANT_BOOL m_bColumnHasDefault;
|
|
WCHAR m_szColumnDefault[129];
|
|
ULONG m_ulColumnFlags;
|
|
VARIANT_BOOL m_bIsNullable;
|
|
USHORT m_nDataType;
|
|
GUID m_guidType;
|
|
DBLENGTH m_ulCharMaxLength;
|
|
ULONG m_ulCharOctetLength;
|
|
USHORT m_nNumericPrecision;
|
|
short m_nNumericScale;
|
|
ULONG m_ulDateTimePrecision;
|
|
WCHAR m_szCharSetCatalog[129];
|
|
WCHAR m_szCharSetSchema[129];
|
|
WCHAR m_szCharSetName[129];
|
|
WCHAR m_szCollationCatalog[129];
|
|
WCHAR m_szCollationSchema[129];
|
|
WCHAR m_szCollationName[129];
|
|
WCHAR m_szDomainCatalog[129];
|
|
WCHAR m_szDomainSchema[129];
|
|
WCHAR m_szDomainName[129];
|
|
WCHAR m_szDescription[129];
|
|
|
|
CCOLUMNSRow()
|
|
{
|
|
ClearMembers();
|
|
}
|
|
|
|
void ClearMembers()
|
|
{
|
|
m_szTableCatalog[0] = NULL;
|
|
m_szTableSchema[0] = NULL;
|
|
m_szTableName[0] = NULL;
|
|
m_szColumnName[0] = NULL;
|
|
m_guidColumn = GUID_NULL;
|
|
m_ulColumnPropID = 0;
|
|
m_ulOrdinalPosition = 0;
|
|
m_bColumnHasDefault = VARIANT_FALSE;
|
|
m_szColumnDefault[0] = NULL;
|
|
m_ulColumnFlags = 0;
|
|
m_bIsNullable = VARIANT_FALSE;
|
|
m_nDataType = 0;
|
|
m_guidType = GUID_NULL;
|
|
m_ulCharMaxLength = 0;
|
|
m_ulCharOctetLength = 0;
|
|
m_nNumericPrecision = 0;
|
|
m_nNumericScale = 0;
|
|
m_ulDateTimePrecision = 0;
|
|
m_szCharSetCatalog[0] = NULL;
|
|
m_szCharSetSchema[0] = NULL;
|
|
m_szCharSetName[0] = NULL;
|
|
m_szCollationCatalog[0] = NULL;
|
|
m_szCollationSchema[0] = NULL;
|
|
m_szCollationName[0] = NULL;
|
|
m_szDomainCatalog[0] = NULL;
|
|
m_szDomainSchema[0] = NULL;
|
|
m_szDomainName[0] = NULL;
|
|
m_szDescription[0] = NULL;
|
|
}
|
|
|
|
|
|
BEGIN_PROVIDER_COLUMN_MAP(CCOLUMNSRow)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_CATALOG", 1, m_szTableCatalog)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_SCHEMA", 2, m_szTableSchema)
|
|
PROVIDER_COLUMN_ENTRY("TABLE_NAME", 3, m_szTableName)
|
|
PROVIDER_COLUMN_ENTRY("COLUMN_NAME", 4, m_szColumnName)
|
|
PROVIDER_COLUMN_ENTRY("COLUMN_GUID",5, m_guidColumn)
|
|
PROVIDER_COLUMN_ENTRY("COLUMN_PROPID",6, m_ulColumnPropID)
|
|
PROVIDER_COLUMN_ENTRY("ORDINAL_POSITION",7, m_ulOrdinalPosition)
|
|
PROVIDER_COLUMN_ENTRY("COLUMN_HASDEFAULT",8, m_bColumnHasDefault)
|
|
PROVIDER_COLUMN_ENTRY("COLUMN_DEFAULT",9, m_szColumnDefault)
|
|
PROVIDER_COLUMN_ENTRY("COLUMN_FLAGS",10, m_ulColumnFlags)
|
|
PROVIDER_COLUMN_ENTRY("IS_NULLABLE",11, m_bIsNullable)
|
|
PROVIDER_COLUMN_ENTRY("DATA_TYPE",12, m_nDataType)
|
|
PROVIDER_COLUMN_ENTRY("TYPE_GUID",13, m_guidType)
|
|
PROVIDER_COLUMN_ENTRY("CHARACTER_MAXIMUM_LENGTH",14, m_ulCharMaxLength)
|
|
PROVIDER_COLUMN_ENTRY("CHARACTER_OCTET_LENGTH",15, m_ulCharOctetLength)
|
|
PROVIDER_COLUMN_ENTRY("NUMERIC_PRECISION",16, m_nNumericPrecision)
|
|
PROVIDER_COLUMN_ENTRY("NUMERIC_SCALE",17, m_nNumericScale)
|
|
PROVIDER_COLUMN_ENTRY("DATETIME_PRECISION",18, m_ulDateTimePrecision)
|
|
PROVIDER_COLUMN_ENTRY("CHARACTER_SET_CATALOG", 19, m_szCharSetCatalog)
|
|
PROVIDER_COLUMN_ENTRY("CHARACTER_SET_SCHEMA", 20, m_szCharSetSchema)
|
|
PROVIDER_COLUMN_ENTRY("CHARACTER_SET_NAME", 21, m_szCharSetName)
|
|
PROVIDER_COLUMN_ENTRY("COLLATION_CATALOG", 22, m_szCollationCatalog)
|
|
PROVIDER_COLUMN_ENTRY("COLLATION_SCHEMA", 23, m_szCollationSchema)
|
|
PROVIDER_COLUMN_ENTRY("COLLATION_NAME", 24, m_szCollationName)
|
|
PROVIDER_COLUMN_ENTRY("DOMAIN_CATALOG", 25, m_szDomainCatalog)
|
|
PROVIDER_COLUMN_ENTRY("DOMAIN_SCHEMA", 26, m_szDomainSchema)
|
|
PROVIDER_COLUMN_ENTRY("DOMAIN_NAME", 27, m_szDomainName)
|
|
PROVIDER_COLUMN_ENTRY("DESCRIPTION", 28, m_szDescription)
|
|
END_PROVIDER_COLUMN_MAP()
|
|
};
|
|
|
|
template <class ArrayClass>
|
|
HRESULT InitFromRowset(ArrayClass& rgData, DBID* pTableID, DBID* pIndexID, IUnknown* pSession, LONG* pcRowsAffected)
|
|
{
|
|
CComQIPtr<IOpenRowset> spOpenRowset = pSession;
|
|
if (spOpenRowset == NULL)
|
|
return E_FAIL;
|
|
CComPtr<IColumnsInfo> spColInfo;
|
|
HRESULT hr = spOpenRowset->OpenRowset(NULL, pTableID, pIndexID, IID_IColumnsInfo, 0, NULL, (IUnknown**)&spColInfo);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
LPOLESTR szColumns = NULL;
|
|
DBORDINAL cColumns = 0;
|
|
DBCOLUMNINFO* pColInfo = NULL;
|
|
hr = spColInfo->GetColumnInfo(&cColumns, &pColInfo, &szColumns);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
*pcRowsAffected = 0;
|
|
for (ULONG iCol = 0; iCol < cColumns; iCol++)
|
|
{
|
|
CCOLUMNSRow crData;
|
|
DBCOLUMNINFO& rColCur = pColInfo[iCol];
|
|
lstrcpynW(crData.m_szTableName, pTableID->uName.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szTableName));
|
|
lstrcpynW(crData.m_szColumnName, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName));
|
|
lstrcpynW(crData.m_szDescription, rColCur.pwszName, SIZEOF_MEMBER(CCOLUMNSRow, m_szColumnName));
|
|
GUID* pGuidCol = CDBIDOps::GetDBIDpGuid(rColCur.columnid);
|
|
if (pGuidCol)
|
|
crData.m_guidColumn = *pGuidCol;
|
|
else
|
|
crData.m_guidColumn = GUID_NULL;
|
|
crData.m_ulColumnPropID = CDBIDOps::GetPropIDFromDBID(rColCur.columnid);
|
|
crData.m_ulOrdinalPosition = rColCur.iOrdinal;
|
|
crData.m_ulColumnFlags = rColCur.dwFlags;
|
|
crData.m_bIsNullable = (rColCur.dwFlags & DBCOLUMNFLAGS_ISNULLABLE) ? VARIANT_TRUE : VARIANT_FALSE;
|
|
crData.m_nDataType = rColCur.wType;
|
|
crData.m_ulCharMaxLength = rColCur.ulColumnSize;
|
|
crData.m_nNumericPrecision = rColCur.bPrecision;
|
|
crData.m_nNumericScale = rColCur.bScale;
|
|
if (!rgData.Add(crData))
|
|
{
|
|
CoTaskMemFree(pColInfo);
|
|
CoTaskMemFree(szColumns);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
*pcRowsAffected++;
|
|
}
|
|
|
|
CoTaskMemFree(pColInfo);
|
|
CoTaskMemFree(szColumns);
|
|
return S_OK;
|
|
}
|
|
|
|
class CPROVIDER_TYPERow
|
|
{
|
|
public:
|
|
// Attributes
|
|
WCHAR m_szName[129];
|
|
USHORT m_nType;
|
|
ULONG m_ulSize;
|
|
WCHAR m_szPrefix[129];
|
|
WCHAR m_szSuffix[129];
|
|
WCHAR m_szCreateParams[129];
|
|
VARIANT_BOOL m_bIsNullable;
|
|
VARIANT_BOOL m_bCaseSensitive;
|
|
ULONG m_bSearchable;
|
|
VARIANT_BOOL m_bUnsignedAttribute;
|
|
VARIANT_BOOL m_bFixedPrecScale;
|
|
VARIANT_BOOL m_bAutoUniqueValue;
|
|
WCHAR m_szLocalTypeName[129];
|
|
short m_nMinScale;
|
|
short m_nMaxScale;
|
|
GUID m_guidType;
|
|
WCHAR m_szTypeLib[129];
|
|
WCHAR m_szVersion[129];
|
|
VARIANT_BOOL m_bIsLong;
|
|
VARIANT_BOOL m_bBestMatch;
|
|
VARIANT_BOOL m_bIsFixedLength;
|
|
|
|
CPROVIDER_TYPERow()
|
|
{
|
|
m_szName[0] = NULL;
|
|
m_nType = 0;
|
|
m_ulSize = 0;
|
|
m_szPrefix[0] = NULL;
|
|
m_szSuffix[0] = NULL;
|
|
m_szCreateParams[0] = NULL;
|
|
m_bIsNullable = VARIANT_FALSE;
|
|
m_bCaseSensitive = VARIANT_FALSE;
|
|
m_bSearchable = DB_UNSEARCHABLE;
|
|
m_bUnsignedAttribute = VARIANT_FALSE;
|
|
m_bFixedPrecScale = VARIANT_FALSE;
|
|
m_bAutoUniqueValue = VARIANT_FALSE;
|
|
m_szLocalTypeName[0] = NULL;
|
|
m_nMinScale = 0;
|
|
m_nMaxScale = 0;
|
|
m_guidType = GUID_NULL;
|
|
m_szTypeLib[0] = NULL;
|
|
m_szVersion[0] = NULL;
|
|
m_bIsLong = VARIANT_FALSE;
|
|
m_bBestMatch = VARIANT_FALSE;
|
|
m_bIsFixedLength = VARIANT_FALSE;
|
|
}
|
|
// Binding Maps
|
|
BEGIN_PROVIDER_COLUMN_MAP(CPROVIDER_TYPERow)
|
|
PROVIDER_COLUMN_ENTRY("TYPE_NAME", 1, m_szName)
|
|
PROVIDER_COLUMN_ENTRY("DATA_TYPE", 2, m_nType)
|
|
PROVIDER_COLUMN_ENTRY("COLUMN_SIZE", 3, m_ulSize)
|
|
PROVIDER_COLUMN_ENTRY("LITERAL_PREFIX", 4, m_szPrefix)
|
|
PROVIDER_COLUMN_ENTRY("LITERAL_SUFFIX", 5, m_szSuffix)
|
|
PROVIDER_COLUMN_ENTRY("CREATE_PARAMS", 6, m_szCreateParams)
|
|
PROVIDER_COLUMN_ENTRY("IS_NULLABLE", 7, m_bIsNullable)
|
|
PROVIDER_COLUMN_ENTRY("CASE_SENSITIVE", 8, m_bCaseSensitive)
|
|
PROVIDER_COLUMN_ENTRY("SEARCHABLE", 9, m_bSearchable)
|
|
PROVIDER_COLUMN_ENTRY("UNSIGNED_ATTRIBUTE", 10, ,m_bUnsignedAttribute)
|
|
PROVIDER_COLUMN_ENTRY("FIXED_PREC_SCALE", 11, m_bFixedPrecScale)
|
|
PROVIDER_COLUMN_ENTRY("AUTO_UNIQUE_VALUE", 12, m_bAutoUniqueValue)
|
|
PROVIDER_COLUMN_ENTRY("LOCAL_TYPE_NAME", 13, m_szLocalTypeName)
|
|
PROVIDER_COLUMN_ENTRY("MINIMUM_SCALE", 14, m_nMinScale)
|
|
PROVIDER_COLUMN_ENTRY("MAXIMUM_SCALE", 15, m_nMaxScale)
|
|
PROVIDER_COLUMN_ENTRY("GUID", 16, m_guidType)
|
|
PROVIDER_COLUMN_ENTRY("TYPELIB", 17, m_szTypeLib)
|
|
PROVIDER_COLUMN_ENTRY("VERSION", 18, m_szVersion)
|
|
PROVIDER_COLUMN_ENTRY("IS_LONG", 19, m_bIsLong)
|
|
PROVIDER_COLUMN_ENTRY("BEST_MATCH", 20, m_bBestMatch)
|
|
PROVIDER_COLUMN_ENTRY("IS_FIXEDLENGTH", 21, m_bIsFixedLength)
|
|
END_PROVIDER_COLUMN_MAP()
|
|
};
|
|
|
|
|
|
class CEnumRowsetImpl
|
|
{
|
|
public:
|
|
|
|
WCHAR m_szSourcesName[256];
|
|
WCHAR m_szSourcesParseName[256];
|
|
WCHAR m_szSourcesDescription[256];
|
|
unsigned short m_iType;
|
|
VARIANT_BOOL m_bIsParent;
|
|
|
|
BEGIN_PROVIDER_COLUMN_MAP(CEnumRowsetImpl)
|
|
PROVIDER_COLUMN_ENTRY("SOURCES_NAME", 1, m_szSourcesName)
|
|
PROVIDER_COLUMN_ENTRY("SOURCES_PARSENAME", 2, m_szSourcesParseName)
|
|
PROVIDER_COLUMN_ENTRY("SOURCES_DESCRIPTION", 3, m_szSourcesDescription)
|
|
PROVIDER_COLUMN_ENTRY("SOURCES_TYPE", 4, m_iType)
|
|
PROVIDER_COLUMN_ENTRY("SOURCES_ISPARENT", 5, m_bIsParent)
|
|
END_PROVIDER_COLUMN_MAP()
|
|
|
|
};
|
|
|
|
#endif
|