Obsługa zestawów wierszy schematu
Zestawy wierszy schematu umożliwiają konsumentom uzyskiwanie informacji o magazynie danych bez znajomości jego podstawowej struktury lub schematu. Na przykład magazyn danych może zawierać tabele zorganizowane w hierarchię zdefiniowaną przez użytkownika, więc nie byłoby możliwości zapewnienia wiedzy o schemacie z wyjątkiem odczytywania go. (W innym przykładzie kreatorzy języka Visual C++ używają zestawów wierszy schematu do generowania metod dostępu dla użytkownika). Aby umożliwić konsumentowi to zrobić, obiekt sesji dostawcy uwidacznia metody w interfejsie IDBSchemaRowset . W aplikacjach Visual C++ użyjesz klasy IDBSchemaRowsetImpl do zaimplementowania klasy IDBSchemaRowset
.
IDBSchemaRowsetImpl
obsługuje następujące metody:
CheckRestrictions sprawdza poprawność ograniczeń względem zestawu wierszy schematu.
CreateSchemaRowset implementuje funkcję twórcy obiektu COM dla obiektu określonego przez parametr szablonu.
SetRestrictions określa, które ograniczenia są obsługiwane w określonym zestawie wierszy schematu.
IDBSchemaRowset::GetRowset zwraca zestaw wierszy schematu (dziedziczony z interfejsu).
Polecenie GetSchemas zwraca listę zestawów wierszy schematu dostępnych przez
IDBSchemaRowsetImpl::GetRowset
(dziedziczone z interfejsu).
Obsługa kreatora dostawcy OLE DB ATL
Kreator dostawcy OLE DB ATL nie jest dostępny w programie Visual Studio 2019 i nowszych wersjach.
Kreator dostawcy OLE DB ATL tworzy trzy klasy schematu w pliku nagłówka sesji:
CShortNameSessionTRSchemaRowset
CShortNameSessionColSchemaRowset
CShortNameSessionPTSchemaRowset
Te klasy odpowiadają na żądania konsumentów dotyczące informacji o schemacie; Należy pamiętać, że specyfikacja OLE DB wymaga obsługi tych trzech zestawów wierszy schematu:
CShortNameSessionTRSchemaRowset obsługuje żądania informacji o tabeli (zestaw wierszy schematu DBSCHEMA_TABLES).
CShortNameSessionColSchemaRowset obsługuje żądania informacji o kolumnie (zestaw wierszy schematu DBSCHEMA_COLUMNS). Kreator dostarcza przykładowe implementacje dla tych klas, które zwracają informacje o schemacie dostawcy usługi DOS.
CShortNameSessionPTSchemaRowset obsługuje żądania dotyczące informacji o schemacie o typie dostawcy (zestaw wierszy schematu DBSCHEMA_PROVIDER_TYPES). Domyślna implementacja dostarczana przez kreatora zwraca S_OK.
Te klasy można dostosować, aby obsługiwać informacje o schemacie odpowiednie dla dostawcy:
W CShortNameSessionTRSchemaRowset należy wypełnić pola wykazu, tabeli i opisu (
trData.m_szType
,trData.m_szTable
, itrData.m_szDesc
). W przykładzie wygenerowanym przez kreatora jest używany tylko jeden wiersz (tabela). Inni dostawcy mogą zwrócić więcej niż jedną tabelę.W CShortNameSessionColSchemaRowset należy przekazać nazwę tabeli jako
DBID
.
Ograniczenia ustawień
Ważną koncepcją obsługi zestawów wierszy schematu jest ustawienie ograniczeń, które są używane w programie SetRestrictions
. Ograniczenia umożliwiają konsumentom pobieranie tylko pasujących wierszy (na przykład znajdowanie wszystkich kolumn w tabeli "MyTable"). Ograniczenia są opcjonalne, a w przypadku, gdy żadna z nich nie jest obsługiwana (wartość domyślna), wszystkie dane są zawsze zwracane. Aby zapoznać się z przykładem dostawcy, który obsługuje ograniczenia, zobacz przykład UpdatePV .
Konfigurowanie mapy schematu
Skonfiguruj mapę schematu, taką jak ta w pliku Session.h w usłudze UpdatePV:
BEGIN_SCHEMA_MAP(CUpdateSession)
SCHEMA_ENTRY(DBSCHEMA_TABLES, CUpdateSessionTRSchemaRowset)
SCHEMA_ENTRY(DBSCHEMA_COLUMNS, CUpdateSessionColSchemaRowset)
SCHEMA_ENTRY(DBSCHEMA_PROVIDER_TYPES, CUpdateSessionPTSchemaRowset)
END_SCHEMA_MAP()
Aby obsługiwać IDBSchemaRowset
program , musisz obsługiwać DBSCHEMA_TABLES, DBSCHEMA_COLUMNS i DBSCHEMA_PROVIDER_TYPES. Możesz dodać dodatkowe zestawy wierszy schematu według własnego uznania.
Zadeklaruj klasę zestawu wierszy schematu za pomocą Execute
metody, takiej jak CUpdateSessionTRSchemaRowset
w pliku UpdatePV
:
class CUpdateSessionTRSchemaRowset :
public CSchemaRowsetImpl < CUpdateSessionTRSchemaRowset,
CTABLESRow, CUpdateSession >
...
// Execute looks like this; what pointers does the consumer use?
HRESULT Execute(DBROWCOUNT* pcRowsAffected,
ULONG cRestrictions, const VARIANT* rgRestrictions)
CUpdateSession
dziedziczy z IDBSchemaRowsetImpl
klasy , więc ma wszystkie metody obsługi ograniczeń. Za pomocą metody CSchemaRowsetImpl
zadeklaruj trzy klasy podrzędne (wymienione na powyższej mapie schematu): CUpdateSessionTRSchemaRowset
, CUpdateSessionColSchemaRowset
i CUpdateSessionPTSchemaRowset
. Każda z tych klas podrzędnych ma metodę Execute
, która obsługuje odpowiedni zestaw ograniczeń (kryteria wyszukiwania). Każda Execute
metoda porównuje wartości parametrów cRestrictions i rgRestrictions . Zobacz opis tych parametrów w temacie SetRestrictions.
Aby uzyskać więcej informacji na temat ograniczeń odpowiadających określonemu zestawowi wierszy schematu, zobacz tabelę identyfikatorów GUID zestawu wierszy schematu w zestawie IDBSchemaRowset w dokumentacji programisty OLE DB w zestawie Windows SDK.
Jeśli na przykład obsługiwane jest ograniczenie TABLE_NAME dotyczące DBSCHEMA_TABLES, należy wykonać następujące czynności:
Najpierw wyszukaj DBSCHEMA_TABLES i sprawdź, czy obsługuje cztery ograniczenia (w kolejności).
Ograniczenie zestawu wierszy schematu | Wartość ograniczenia |
---|---|
TABLE_CATALOG | 0x1 (binarny 1) |
TABLE_SCHEMA | 0x2 (binarny 10) |
TABLE_NAME | 0x4 (binarny 100) |
TABLE_TYPE | 0x8 (binarny 1000) |
Następnie istnieje jeden bit dla każdego ograniczenia. Ponieważ chcesz obsługiwać tylko TABLE_NAME, należy zwrócić 0x4 w elemecie rgRestrictions
. Jeśli obsługiwane są TABLE_CATALOG i TABLE_NAME, należy zwrócić 0x5 (binarny 101).
Domyślnie implementacja zwraca wartość 0 (nie obsługuje żadnych ograniczeń) dla żadnego żądania. UpdatePV to przykład dostawcy, który obsługuje ograniczenia.
Przykład
Ten kod jest pobierany z przykładu UpdatePV . UpdatePv
obsługuje trzy wymagane zestawy wierszy schematu: DBSCHEMA_TABLES, DBSCHEMA_COLUMNS i DBSCHEMA_PROVIDER_TYPES. Jako przykład implementacji obsługi schematu u dostawcy w tym temacie przedstawiono implementację zestawu wierszy DBSCHEMA_TABLE.
Uwaga
Przykładowy kod może się różnić od tego, co jest tutaj wymienione; Przykładowy kod powinien być traktowany jako bardziej aktualna wersja.
Pierwszym krokiem w dodawaniu obsługi schematu jest określenie, które ograniczenia mają być obsługiwane. Aby określić, które ograniczenia są dostępne dla zestawu wierszy schematu, zapoznaj się ze specyfikacją OLE DB dla definicji .IDBSchemaRowset
Po definicji głównej zostanie wyświetlona tabela zawierająca nazwę zestawu wierszy schematu, liczbę ograniczeń i kolumny ograniczeń. Wybierz zestaw wierszy schematu, który chcesz obsługiwać, i zanotuj liczbę ograniczeń i kolumn ograniczeń. Na przykład usługa DBSCHEMA_TABLES obsługuje cztery ograniczenia (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME i TABLE_TYPE):
void SetRestrictions(ULONG cRestrictions, GUID* rguidSchema,
ULONG* rgRestrictions)
{
for (ULONG l=0; l<cRestrictions; l++)
{
if (InlineIsEqualGUID(rguidSchema[l], DBSCHEMA_TABLES))
rgRestrictions[l] = 0x0C;
else if (InlineIsEqualGUID(rguidSchema[l], DBSCHEMA_COLUMNS))
rgRestrictions[l] = 0x04;
else if (InlineIsEqualGUID(rguidSchema[l],
DBSCHEMA_PROVIDER_TYPES))
rgRestrictions[l] = 0x00;
}
}
Bit reprezentuje każdą kolumnę ograniczeń. Jeśli chcesz obsługiwać ograniczenie (czyli możesz wykonać zapytanie według niego), ustaw ten bit na wartość 1. Jeśli nie chcesz obsługiwać ograniczenia, ustaw ten bit na zero. W powyższym UpdatePV
wierszu kodu obsługuje ograniczenia TABLE_NAME i TABLE_TYPE dotyczące zestawu wierszy DBSCHEMA_TABLES. Są to trzecie ograniczenia (maska bitowa 100) i czwarta (maska bitowa 1000). W związku z tym maska bitów dla UpdatePv
parametru to 1100 (lub 0x0C):
if (InlineIsEqualGUID(rguidSchema[l], DBSCHEMA_TABLES))
rgRestrictions[l] = 0x0C;
Poniższa funkcja jest podobna do tych Execute
w zwykłych zestawach wierszy. Istnieją trzy argumenty: pcRowsAffected, cRestrictions i rgRestrictions. Zmienna pcRowsAffected jest parametrem wyjściowym, który dostawca może zwrócić liczbę wierszy w zestawie wierszy schematu. Parametr cRestrictions jest parametrem wejściowym, który przechowuje liczbę ograniczeń przekazanych przez konsumenta do dostawcy. Parametr rgRestrictions jest tablicą wartości VARIANT, które przechowują wartości ograniczeń.
HRESULT Execute(DBROWCOUNT* pcRowsAffected, ULONG cRestrictions,
const VARIANT* rgRestrictions)
Zmienna cRestrictions jest oparta na łącznej liczbie ograniczeń dla zestawu wierszy schematu, niezależnie od tego, czy dostawca je obsługuje. Ponieważ protokół UpdatePv obsługuje dwa ograniczenia (trzeci i czwarty), ten kod szuka tylko wartości cRestrictions większej lub równej trzem.
Wartość ograniczenia TABLE_NAME jest przechowywana w rgRestrictions[2] (ponownie trzecie ograniczenie w tablicy opartej na zera wynosi 2). Sprawdź, czy ograniczenie nie jest VT_EMPTY, aby rzeczywiście je obsługiwać. Należy pamiętać, że VT_NULL nie jest równa VT_EMPTY. VT_NULL określa prawidłową wartość ograniczenia.
Definicja UpdatePv
nazwy tabeli jest w pełni kwalifikowaną nazwą ścieżki do pliku tekstowego. Wyodrębnij wartość ograniczenia, a następnie spróbuj otworzyć plik, aby upewnić się, że plik rzeczywiście istnieje. Jeśli plik nie istnieje, zwróć S_OK. Może to wydawać się nieco wstecz, ale kod naprawdę mówi konsumentowi, że nie było obsługiwanych tabel według określonej nazwy. Zwracany S_OK oznacza, że kod został wykonany poprawnie.
USES_CONVERSION;
enum {
sizeOfszFile = 255
};
CTABLESRow trData;
FILE *pFile = NULL;
TCHAR szFile[ sizeOfszFile ];
errcode err = 0;
// Handle any restrictions sent to us. This only handles
// the TABLE_NAME & TABLE_TYPE restictions (the 3rd and 4th
// restrictions in DBSCHEMA_TABLES...look in IDBSchemaRowsets
// in part 2 of the prog. ref) so your restrictions are 0x08 & 0x04
// for a total of (0x0C)
if (cRestrictions >= 3 && rgRestrictions[2].vt != VT_EMPTY)
{
CComBSTR bstrName = rgRestrictions[2].bstrVal;
if ((rgRestrictions[2].vt == VT_BSTR) && (bstrName != (BSTR)NULL))
{
// Check to see if the file exists
_tcscpy_s(&szFile[0], sizeOfszFile, OLE2T(bstrName));
if (szFile[0] == _T('\0') ||
((err = _tfopen(&pFile, &szFile[0], _T("r"))) == 0))
{
return S_OK;// Their restriction was invalid return no data
}
else
{
fclose(pFile);
}
}
}
Wspieranie czwartego ograniczenia (TABLE_TYPE) jest podobne do trzeciego ograniczenia. Sprawdź, czy wartość nie jest VT_EMPTY. To ograniczenie zwraca tylko typ tabeli TABLE. Aby określić prawidłowe wartości dla DBSCHEMA_TABLES, zapoznaj się z załącznikiem B odwołania programisty OLE DB w sekcji zestaw wierszy TABEL.
// TABLE_TYPE restriction:
if (cRestrictions >=4 && rgRestrictions[3].vt != VT_EMPTY)
{
CComBSTR bstrType = rgRestrictions[3].bstrVal;
if ((rgRestrictions[3].vt == VT_BSTR) && (bstrType != (BSTR)NULL))
{
// This is kind of a blind restriction.
// This only actually supports
// TABLES so if you get anything else,
// just return an empty rowset.
if (_tcscmp(_T("TABLE"), OLE2T(bstrType)) != 0)
return S_OK;
}
}
W tym miejscu faktycznie utworzysz wpis wiersza dla zestawu wierszy. Zmienna trData
odpowiada CTABLESRow
strukturze zdefiniowanej w szablonach dostawców OLE DB. CTABLESRow
odpowiada definicji zestawu wierszy TABLES w dodatku B specyfikacji OLE DB. Do dodania jest tylko jeden wiersz, ponieważ jednocześnie można obsługiwać tylko jedną tabelę.
// Bring over the data:
wcspy_s(trData.m_szType, OLESTR("TABLE"), 5);
wcspy_s(trData.m_szDesc, OLESTR("The Directory Table"), 19);
wcsncpy_s(trData.m_szTable, T2OLE(szFile), _TRUNCATE());
UpdatePV
ustawia tylko trzy kolumny: TABLE_NAME, TABLE_TYPE i DESCRIPTION. Zanotuj kolumny, dla których zwracasz informacje, ponieważ te informacje są potrzebne podczas implementowania polecenia GetDBStatus
:
_ATLTRY
{
m_rgRowData.Add(trData);
}
_ATLCATCHALL()
{
return E_OUTOFMEMORY;
}
//if (!m_rgRowData.Add(trData))
// return E_OUTOFMEMORY;
*pcRowsAffected = 1;
return S_OK;
}
Funkcja GetDBStatus
jest ważna dla prawidłowej operacji zestawu wierszy schematu. Ponieważ nie zwracasz danych dla każdej kolumny w zestawie wierszy TABEL, musisz określić, dla których kolumn zwracane są dane, a których nie.
virtual DBSTATUS GetDBStatus(CSimpleRow* , ATLCOLUMNINFO* pColInfo)
{
ATLASSERT(pColInfo != NULL);
switch(pColInfo->iOrdinal)
{
case 3: // TABLE_NAME
case 4: // TABLE_TYPE
case 6: // DESCRIPTION
return DBSTATUS_S_OK;
break;
default:
return DBSTATUS_S_ISNULL;
break;
}
}
Execute
Ponieważ funkcja zwraca dane dla pól TABLE_NAME, TABLE_TYPE i DESCRIPTION z zestawu wierszy TABEL, możesz wyszukać w dodatku B specyfikacji OLE DB i określić (licząc od góry w dół), że są one zwykle 3, 4 i 6. Dla każdej z tych kolumn zwróć DBSTATUS_S_OK. Dla wszystkich pozostałych kolumn zwróć DBSTATUS_S_ISNULL. Należy zwrócić ten stan, ponieważ użytkownik może nie zrozumieć, że zwracana wartość ma wartość NULL lub coś innego. Ponownie należy pamiętać, że wartość NULL nie jest równoważna pustemu.
Aby uzyskać więcej informacji na temat interfejsu zestawu wierszy schematu OLE DB, zobacz interfejs IDBSchemaRowset w dokumentacji programisty OLE DB.
Aby uzyskać informacje o sposobie używania metod przez użytkowników, zobacz Uzyskiwanie metadanych przy użyciu IDBSchemaRowset
zestawów wierszy schematu.
Przykład dostawcy obsługującego zestawy wierszy schematu można znaleźć w przykładzie UpdatePV .