WindowsXP/net/ias/sdo/datastore2/oledb/oledbstore.cpp
2025-04-27 07:49:33 -04:00

335 lines
8.2 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1998, Microsoft Corp. All rights reserved.
//
// FILE
//
// oledbstore.cpp
//
// SYNOPSIS
//
// This file defines the class OleDBDataStore.
//
// MODIFICATION HISTORY
//
// 02/20/1998 Original version.
// 03/17/1999 Create TMP dir before calling IDBInitialize::Initialize.
// 05/05/1999 Disable row-level locking.
// 05/25/1999 Check version when connecting.
// 01/25/2000 Increase MAX_VERSION to 1.
//
///////////////////////////////////////////////////////////////////////////////
#include <ias.h>
#include <iasutil.h>
#include <dsobject.h>
#include <oledbstore.h>
#include <propset.h>
#include <msjetoledb.h>
#include <oledberr.h>
//////////
// Execute an arbitrary SQL statement.
//////////
HRESULT
WINAPI
IASExecuteSQLCommand(
LPUNKNOWN session,
PCWSTR commandText,
IRowset** result
)
{
HRESULT hr;
CComPtr<IDBCreateCommand> creator;
hr = session->QueryInterface(
__uuidof(IDBCreateCommand),
(PVOID*)&creator
);
if (FAILED(hr)) { return hr; }
CComPtr<ICommandText> command;
hr = creator->CreateCommand(
NULL,
__uuidof(ICommandText),
(IUnknown**)&command
);
if (FAILED(hr)) { return hr; }
hr = command->SetCommandText(
DBGUID_DBSQL,
commandText
);
if (FAILED(hr)) { return hr; }
return command->Execute(
NULL,
__uuidof(IRowset),
NULL,
NULL,
(IUnknown**)result
);
}
//////////
// Execute an SQL statement that returns a single integer.
//////////
HRESULT
WINAPI
IASExecuteSQLFunction(
LPUNKNOWN session,
PCWSTR functionText,
LONG* result
)
{
// Execute the function.
HRESULT hr;
CComPtr<IRowset> rowset;
hr = IASExecuteSQLCommand(
session,
functionText,
&rowset
);
if (FAILED(hr)) { return hr; }
CComPtr<IAccessor> accessor;
hr = rowset->QueryInterface(
__uuidof(IAccessor),
(PVOID*)&accessor
);
if (FAILED(hr)) { return hr; }
// Get the result row.
DBCOUNTITEM numRows;
HROW hRow;
HROW* pRow = &hRow;
hr = rowset->GetNextRows(
NULL,
0,
1,
&numRows,
&pRow
);
if (FAILED(hr)) { return hr; }
if (numRows == 0) { return E_FAIL; }
/////////
// Create an accessor.
/////////
DBBINDING bind;
memset(&bind, 0, sizeof(bind));
bind.iOrdinal = 1;
bind.dwPart = DBPART_VALUE;
bind.wType = DBTYPE_I4;
bind.cbMaxLen = 4;
HACCESSOR hAccess;
hr = accessor->CreateAccessor(
DBACCESSOR_ROWDATA,
1,
&bind,
4,
&hAccess,
NULL
);
if (SUCCEEDED(hr))
{
// Get the data.
hr = rowset->GetData(
hRow,
hAccess,
result
);
accessor->ReleaseAccessor(hAccess, NULL);
}
rowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
return hr;
}
//////////
// ProgID of the OLE-DB provider that will be used.
//////////
const wchar_t PROVIDER[] = L"Microsoft.Jet.OLEDB.4.0";
//////////
// Current versions supported.
//////////
const LONG MIN_VERSION = 0;
const LONG MAX_VERSION = 2;
STDMETHODIMP OleDBDataStore::get_Root(IDataStoreObject** ppObject)
{
if (ppObject == NULL) { return E_INVALIDARG; }
if (*ppObject = root) { (*ppObject)->AddRef(); }
return S_OK;
}
STDMETHODIMP OleDBDataStore::Initialize(BSTR bstrDSName,
BSTR bstrUserName,
BSTR bstrPassword)
{
if (root != NULL)
{
HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
}
// Convert the ProgID to a ClsID.
CLSID clsid;
RETURN_ERROR(CLSIDFromProgID(PROVIDER, &clsid));
// Create the OLE DB provider.
RETURN_ERROR(CoCreateInstance(clsid,
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IDBInitialize),
(PVOID*)&connection));
//////////
// Set the properties for the data source.
//////////
CComPtr<IDBProperties> properties;
RETURN_ERROR(connection->QueryInterface(IID_IDBProperties,
(PVOID*)&properties));
DBPropertySet<4> propSet(DBPROPSET_DBINIT);
propSet.AddProperty(DBPROP_INIT_MODE, DB_MODE_READWRITE);
if (bstrDSName) propSet.AddProperty(DBPROP_INIT_DATASOURCE, bstrDSName);
if (bstrUserName) propSet.AddProperty(DBPROP_AUTH_USERID, bstrUserName);
if (bstrPassword) propSet.AddProperty(DBPROP_AUTH_PASSWORD, bstrPassword);
RETURN_ERROR(properties->SetProperties(1, &propSet));
DBPropertySet<1> jetPropSet(DBPROPSET_JETOLEDB_DBINIT);
jetPropSet.AddProperty(
DBPROP_JETOLEDB_DATABASELOCKMODE,
(LONG)DBPROPVAL_DL_OLDMODE
);
RETURN_ERROR(properties->SetProperties(1, &jetPropSet));
//////////
// JetInit fails if the TMP directory doesn't exist, so we'll try to
// create it just in case.
//////////
DWORD needed = GetEnvironmentVariableW(L"TMP", NULL, 0);
if (needed)
{
PWCHAR buf = (PWCHAR)_alloca(needed * sizeof(WCHAR));
DWORD actual = GetEnvironmentVariableW(L"TMP", buf, needed);
if (actual > 0 && actual < needed)
{
CreateDirectoryW(buf, NULL);
}
}
//////////
// Initialize the connection.
//////////
RETURN_ERROR(connection->Initialize());
//////////
// Create a session.
//////////
CComPtr<IDBCreateSession> creator;
RETURN_ERROR(connection->QueryInterface(__uuidof(IDBCreateSession),
(PVOID*)&creator));
RETURN_ERROR(creator->CreateSession(NULL, __uuidof(IUnknown), &session));
//////////
// Check the version.
//////////
LONG version;
HRESULT hr = IASExecuteSQLFunction(
session,
L"SELECT Version FROM Version",
&version
);
// If the table doesn't exist, then version is zero.
if (hr == DB_E_NOTABLE)
{
version = 0;
}
else if (FAILED(hr))
{
return hr;
}
// Is it out of bounds?
if (version < MIN_VERSION || version > MAX_VERSION)
{
return HRESULT_FROM_WIN32(ERROR_REVISION_MISMATCH);
}
try
{
//////////
// Initialize all the command objects.
//////////
members.initialize(session);
create.initialize(session);
destroy.initialize(session);
find.initialize(session);
update.initialize(session);
erase.initialize(session);
get.initialize(session);
set.initialize(session);
// Create the root object.
root = new DBObject(this, NULL, 1, L"top");
}
CATCH_AND_RETURN()
return S_OK;
}
STDMETHODIMP OleDBDataStore::OpenObject(BSTR bstrPath,
IDataStoreObject** ppObject)
{
return E_NOTIMPL;
}
STDMETHODIMP OleDBDataStore::Shutdown()
{
//////////
// Release the root.
//////////
root.Release();
//////////
// Finalize the commands.
//////////
set.finalize();
get.finalize();
erase.finalize();
update.finalize();
find.finalize();
destroy.finalize();
create.finalize();
members.finalize();
//////////
// Release the data source connection.
//////////
session.Release();
connection.Release();
return S_OK;
}