Cotype TSession
cotype TSession {
[mandatory] interface IGetDataSource;
[mandatory] interface IOpenRowset;
[mandatory] interface ISessionProperties;
[optional] interface IAlterIndex;
[optional] interface IAlterTable;
[optional] interface IBindResource;
[optional] interface ICreateRow;
[optional] interface IDBCreateCommand;
[optional] interface IDBSchemaRowset;
[optional] interface IIndexDefinition;
[optional] interface ISupportErrorInfo;
[optional] interface ITableDefinition;
[optional] interface ITransactionJoin;
[optional] interface ITransactionLocal;
[optional] interface ITransaction;
[optional] interface ITransactionObject;
}
Figure 3 Establishing a Connection
#include <oledb.h> // oledb headers
#include <sqloledb.h> // SQL Server headers
void GetConnection(IUnknown **ppUnkSession,
DBPROPSET *pProperties) {
// load the provider
IDBInitialize *pdbInit;
CoCreateInstance(CLSID_SQLOLEDB, 0, CLSCTX_ALL,
__uuidof(pdbInit), (void**)&pdbInit);
// set the initial properties
IDBProperties *pdbProps;
pdbInit->QueryInterface(&pdbProps);
pdbProps->SetProperties(1, pProperties);
// tell the provider to connect to data source
pdbInit->Initialize();
// create a new session object
IDBCreateSession *pdbcs = 0;
pdbcs->CreateSession(0,
__uuidof(**ppUnkSession),
(IUnknown**)ppUnkSession);
// release intermediate references
pdbInit->Release();
pdbProps->Release();
pdbcs->Release();
}
Figure 4 Sending SQL Commands and OLE DB
void SendSQL(IUnknown *pUnkSession,
const OLECHAR *pwszSQL) {
// ask session to create a new commmand
IDBCreateCommand *pdbcc;
pUnkSession->QueryInterface(&pdbcc);
ICommandText *pCmdTxt;
pdbcc->CreateCommand(0, __uuidof(pCmdText),
(IUnknown**)&pCmdText);
// store SQL statement in command object
pCmdText->SetCommandText(DBGUID_DEFAULT,
pwszSQL);
// ship SQL down to database
pCmdText->Execute(0, GUID_NULL, 0, 0, 0);
// release all resources
pCmdText->Release();
pdbcc->Release();
}
Figure 5 OLE DB Property Sets
Property Set |
Set Via |
Read Via |
DBINIT |
IDBProperties::SetProperties IDBDataSourceAdmin::CreateDataSource IDBDataSourceAdmin::ModifyDataSource |
IDBProperties::GetProperties |
DATASOURCE |
IDBProperties::SetProperties |
IDBProperties::GetProperties |
DATASOURCEINFO |
N/A |
IDBProperties::GetProperties |
TABLE |
ITableDefinition::CreateTable IAlterTable::AlterTable |
ITableCreation::GetTableDefinition |
COLUMN |
ITableDefinition::CreateTable ITableDefinition::AddColumn IAlterTable::AlterColumn |
ITableCreation::GetTableDefinition |
INDEX |
IIndexDefinition::CreateIndex IAlterIndex::AlterIndex |
IRowsetIndex::GetIndexInfo |
SESSION |
ISessionProperties::SetProperties |
ISessionProperties::GetProperties |
ROWSET |
IOpenRowset::OpenRowset ICommandProperties::SetProperties IColumnsRowset::GetColumnsRowset ISourcesRowset::GetSourcesRowset IDBSchemaRowset::GetRowset |
IRowsetInfo::GetProperties ICommandProperties::GetProperties |
Figure 6 Using Properties
// build a vector of three properties
DBPROP rgp[3] = { 0 };
rgp[0].dwPropertyID = DBPROP_AUTH_USERID;
rgp[0].vValue.vt = VT_BSTR;
rgp[0].vValue.bstrVal = SysAllocString(L"sa");
rgp[1].dwPropertyID = DBPROP_AUTH_PASSWORD;
rgp[1].vValue.vt = VT_BSTR;
rgp[1].vValue.bstrVal = SysAllocString(L"");
rgp[2].dwPropertyID = DBPROP_INIT_CATALOG;
rgp[2].vValue.vt = VT_BSTR;
rgp[2].vValue.bstrVal = SysAllocString(L"pubs");
// scope/bind vector with property set GUID
DBPROPSET rgdbpropset[1] = { 0 };
rgdbpropset[0].cProperties = 3;
rgdbpropset[0].rgProperties = rgp;
rgdbpropset[0].guidPropertySet=DBPROPSET_DBINIT;
// pass PROPSET to previous code to init provider
IUnknown *pUnkSession;
GetConnection(&pUnkSession, rgdbpropset);
// clean up
VariantClear(&rgp[0].vValue);
VariantClear(&rgp[1].vValue);
VariantClear(&rgp[2].vValue);
Figure 7 MSDASC.IDL
////////////////////////////////////////////////
// MSDASC.IDL (excerpt)
//
interface IDataInitialize : IUnknown {
// parse initialization string into propset and load datasource
HRESULT GetDataSource(
[in] IUnknown *pUnkOuter,
[in] DWORD dwClsCtx,
[in,unique] LPCOLESTR pwszInitializationString,
[in] REFIID riid,
[in,out,iid_is(riid)] IUnknown **ppDataSource);
// reverse engineer initialization string
HRESULT GetInitializationString(
[in] IUnknown *pDataSource,
[in] boolean fIncludePassword,
[out] LPOLESTR *ppwszInitString);
// create provider using service components
HRESULT CreateDBInstance(
[in] REFCLSID clsidProvider,
[in] IUnknown *pUnkOuter,
[in] DWORD dwClsCtx,
[in,unique] LPOLESTR pwszReserved,
[in] REFIID riid,
[out,iid_is(riid)] IUnknown **ppDataSource);
// create provider using service components
HRESULT CreateDBInstanceEx(
[in] REFCLSID clsidProvider,
[in] IUnknown *pUnkOuter,
[in] DWORD dwClsCtx,
[in,unique] LPOLESTR pwszReserved,
[in,unique] COSERVERINFO *pServerInfo,
[in] ULONG cmq,
[in,out,size_is(cmq)] MULTI_QI *rgmqResults);
// read initialization string from a UDL file
HRESULT LoadStringFromStorage(
[in,unique] LPCOLESTR pwszFileName,
[out] LPOLESTR *ppwszInitializationString);
// write initialization string to a UDL file
HRESULT WriteStringToStorage(
[in,unique] LPCOLESTR pwszFileName,
[in,unique] LPCOLESTR pwszInitializationString,
[in] DWORD dwCreationDisposition);
};
coclass MSDAINITIALIZE {
interface IDataInitialize;
}
Figure 8 Using MSDAINITIALIZE
void GetConnection(IUnknown **ppUnkDataSource) {
// load MSDAINITIALIZE
IDataInitialize *pdi;
CoCreateInstance(CLSID_MSDAINITIALIZE, 0,
CLSCTX_ALL, __uuidof(pdi), (void**)&pdi);
// parse the init string and load provider
IDBInitialize *pdbInit;
pdi->GetDataSource(0, CLSCTX_ALL,
L"PROVIDER=SQLOLEDB;DATABASE=pubs;UID=sa;PWD=",
__uuidof(pdbInit), (IUnknown**)&pdbInit);
// initialize the provider based on parsed props
pdbInit->Initialize();
// clean up
pdi->Release();
(*ppUnkDataSource = pdbInit)->AddRef();
pdbInit->Release();
}
Figure 12 OLEDB.IDL
////////////////////////////////////////////////
// OLEDB.IDL (excerpt)
//
typedef struct tagDBBINDING {
DBORDINAL iOrdinal; // column #
DBBYTEOFFSET obValue; // offset into buffer
DBBYTEOFFSET obLength; // offset into buffer for length
DBBYTEOFFSET obStatus; // error/status code
ITypeInfo *pTypeInfo; // desc of COM object
DBOBJECT *pObject; // IID of COM object ref
DBBINDEXT *pBindExt; // extensions
DBPART dwPart; // value and/or length?
DBMEMOWNER dwMemOwner; // client vs. provider owned
DBPARAMIO eParamIO; // in/out for command parameters
DBLENGTH cbMaxLen; // sub-buffer size
DWORD dwFlags; // HTML?
DBTYPE wType; // Data type (extended VARTYPE)
BYTE bPrecision; // precision for numerics
BYTE bScale; // scale for numerics
} DBBINDING;
interface IAccessor : IUnknown {
HRESULT AddRefAccessor([in] HACCESSOR hAccessor,
[in,out,unique] DBREFCOUNT *pcRefCount) ;
HRESULT CreateAccessor(
[in] DBACCESSORFLAGS dwAccessorFlags,
[in] DBCOUNTITEM cBindings,
[in, size_is(cBindings)] const DBBINDING rgBindings[ ],
[in] DBLENGTH cbRowSize,
[out] HACCESSOR *phAccessor,
[out,size_is(cBindings)] DBBINDSTATUS rgStatus[ ]) ;
HRESULT GetBindings(
[in] HACCESSOR hAccessor,
[out] DBACCESSORFLAGS *pdwAccessorFlags,
[in,out] DBCOUNTITEM *pcBindings,
[out, size_is(*pcBindings)] DBBINDING **prgBindings) ;
HRESULT ReleaseAccessor([in] HACCESSOR hAccessor,
[in,out,unique] DBREFCOUNT *pcRefCount) ;
}
interface IRowset : IUnknown {
HRESULT AddRefRows(
[in] DBCOUNTITEM cRows,
[in,size_is(cRows) ] const HROW rghRows[ ],
[out,size_is(cRows)] DBREFCOUNT rgRefCounts[ ],
[out,size_is(cRows)] DBROWSTATUS rgRowStatus[ ]) ;
HRESULT GetData([in] HROW hRow, [in] HACCESSOR hAccessor,
[out] void *pData) ;
HRESULT GetNextRows(
[in] HCHAPTER hReserved,
[in] DBROWOFFSET lRowsOffset,
[in] DBROWCOUNT cRows,
[out] DBCOUNTITEM *pcRowsObtained,
[size_is][size_is][out] HROW **prghRows) ;
HRESULT ReleaseRows(
[in] DBCOUNTITEM cRows,
[size_is][in] const HROW rghRows[ ],
[size_is][in] DBROWOPTIONS rgRowOptions[ ],
[size_is][out] DBREFCOUNT rgRefCounts[ ],
[size_is][out] DBROWSTATUS rgRowStatus[ ]) ;
HRESULT RestartPosition([in] HCHAPTER hReserved) ;
};
Figure 13 PrintAll.cpp
///////////////////////////////////////////
// Printall.cpp - a simple client that prints
// the result of a select statement
//
#define OLEDBVER 0x0250
#define _WIN32_DCOM
#include <windows.h>
#include <stdio.h>
#include <oledb.h>
#include <msdasc.h>
#include <atlbase.h>
CComModule _Module;
#include <atlcom.h>
// some helper macros
#define CELEMS(rg) (sizeof(rg)/sizeof(*(rg)))
#define sizeofmember(T, m) sizeof( (((T*)16)->m) )
// client representation of a row
struct CUSTOMER
{
CUSTOMER() { *id = *lname = *fname = 0; }
TCHAR id[9];
TCHAR lname[33];
TCHAR fname[33];
};
// description of CUSTOMER representation
DBBINDING rgBindings[] =
{
{ 1, offsetof(CUSTOMER, id), 0, 0, 0, 0, 0, DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED, 0, sizeofmember(CUSTOMER, id),
0, DBTYPE_STR, 0, 0 },
{ 2, offsetof(CUSTOMER, fname), 0, 0, 0, 0, 0, DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED, 0, sizeofmember(CUSTOMER, fname),
0, DBTYPE_STR, 0, 0 },
{ 3, offsetof(CUSTOMER, lname), 0, 0, 0, 0, 0, DBPART_VALUE,
DBMEMOWNER_CLIENTOWNED, 0, sizeofmember(CUSTOMER, lname),
0, DBTYPE_STR, 0, 0 },
};
#define HR(exp) { HRESULT _hr = (exp); if (FAILED(_hr)) return _hr; }
HRESULT PrintAll(const OLECHAR *pwszInitString)
{
// load and initialize the provider
CComPtr<IDataInitialize> pdi;
HR(CoCreateInstance(__uuidof(MSDAINITIALIZE), 0, CLSCTX_ALL, __uuidof(pdi),
(void**)&pdi));
CComPtr<IDBInitialize> dbInit;
HR(pdi->GetDataSource(0, CLSCTX_ALL, pwszInitString,
__uuidof(dbInit), (IUnknown**)&dbInit));
HR(dbInit->Initialize());
// create a new command with our select statement
CComPtr<IDBCreateSession> cs;
HR(dbInit->QueryInterface(&cs));
CComPtr<IDBCreateCommand> cc;
HR(cs->CreateSession(0, __uuidof(cc), (IUnknown**)&cc));
CComPtr<ICommandText> cmd;
HR(cc->CreateCommand(0, __uuidof(cmd), (IUnknown**)&cmd));
HR(cmd->SetCommandText(DBGUID_DEFAULT, L"select * from customers"));
// squirt the SQL down to the database and get back a rowset object
CComPtr<IRowset> rs;
HR(cmd->Execute(0, __uuidof(rs), 0, 0, (IUnknown**)&rs));
// create an accessor for CUSTOMER
CComPtr<IAccessor> acc;
HR(rs->QueryInterface(&acc));
DBSTATUS rgStatus[CELEMS(rgBindings)];
HACCESSOR hAccessor;
HR(acc->CreateAccessor(DBACCESSOR_ROWDATA, CELEMS(rgBindings),
rgBindings, sizeof(CUSTOMER),
&hAccessor, rgStatus));
// walk through the rowset and print each row
bool bDone = false;
HRESULT hr = S_OK;
while (!bDone)
{
const int CHUNKSIZE = 5;
HROW *prgRows = 0;
ULONG cRows;
// fetch CHUNKSIZE rows into provider's buffer
hr = rs->GetNextRows(0, 0, CHUNKSIZE, &cRows, &prgRows);
if (hr != S_OK)
bDone = true;
if (SUCCEEDED(hr))
{
for (ULONG i = 0; SUCCEEDED(hr) && i < cRows; i++)
{
// copy row into client buffer (record) and print
CUSTOMER record;
hr = rs->GetData(prgRows[i], hAccessor, &record);
if (FAILED(hr))
bDone = true;
else
printf("%s: %s %s\n", record.id,
record.fname, record.lname);
}
// clean up
rs->ReleaseRows(cRows, prgRows, 0, 0, 0);
CoTaskMemFree(prgRows);
}
}
acc->ReleaseAccessor(hAccessor, 0);
return hr;
}
int main(int argc, char **argv)
{
HRESULT hr = CoInitializeEx(0, 0);
if (SUCCEEDED(hr))
{
hr = PrintAll(L""PROVIDER=SQLOLEDB;DATABASE=bob;UID=sa;PWD=");
CoUninitialize();
}
return hr;
}