스키마 행 집합 지원
업데이트: 2007년 11월
스키마 행 집합을 사용하면 데이터 저장소의 내부 구조나 스키마에 대한 정보가 없어도 소비자가 데이터 저장소에 대한 정보를 얻을 수 있습니다. 예를 들어, 데이터 저장소에 사용자 정의 계층으로 구성된 테이블이 있고 이 테이블을 읽는 것 외에는 스키마를 알 수 있는 방법이 없는 경우가 있습니다. 또 다른 예로는 Visual C++ 마법사가 스키마 행 집합을 사용하여 소비자에 대한 접근자를 생성하는 것을 들 수 있습니다. 소비자가 데이터 저장소에 대한 정보를 얻을 수 있도록 하기 위해 공급자의 세션 개체가 IDBSchemaRowset 인터페이스에 메서드를 노출합니다. Visual C++ 응용 프로그램에서는 IDBSchemaRowset 클래스를 사용하여 IDBSchemaRowset을 구현합니다.
IDBSchemaRowsetImpl은 다음 메서드를 지원합니다.
CheckRestrictions는 스키마 행 집합에 대해 제한 유효성을 검사합니다.
CreateSchemaRowset은 템플릿 매개 변수로 지정한 개체에 대해 COM 개체 작성자 함수를 구현합니다.
SetRestrictions는 특정 스키마 행 집합에서 지원할 제한을 지정합니다.
IDBSchemaRowset::GetRowset은 인터페이스에서 상속한 스키마 행 집합을 반환합니다.
GetSchemas는 인터페이스에서 상속한 IDBSchemaRowsetImpl::GetRowset이 액세스할 수 있는 스키마 행 집합 목록을 반환합니다.
ATL OLE DB 공급자 마법사 지원
ATL OLE DB 공급자 마법사는 세션 헤더 파일에 세 스키마 클래스를 만듭니다.
CShortNameSessionTRSchemaRowset
CShortNameSessionColSchemaRowset
CShortNameSessionPTSchemaRowset
이 세 클래스는 소비자의 스키마 정보 요청에 응답합니다. OLE DB 사양에 이 세 스키마 행 집합이 지원되어야 한다고 명시되어 있습니다.
CShortNameSessionTRSchemaRowset은 테이블 정보(DBSCHEMA_TABLES 스키마 행 집합)에 대한 요청을 처리합니다.
CShortNameSessionColSchemaRowset은 열 정보(DBSCHEMA_COLUMNS 스키마 행 집합)에 대한 요청을 처리합니다. 마법사가 이러한 클래스에 대해 샘플 구현을 제공하는데, 이 구현이 DOS 공급자에게 스키마 행 집합을 반환합니다.
CShortNameSessionPTSchemaRowset은 공급자 종류(DBSCHEMA_PROVIDER_TYPES 스키마 행 집합)에 대한 스키마 정보에 대하여 요청을 처리합니다. 마법사가 제공하는 기본 구현은 S_OK를 반환합니다.
이 세 클래스를 사용자 지정하여 공급자에 적절한 스키마 정보를 처리할 수 있습니다.
CShortNameSessionTRSchemaRowset에서 카탈로그, 테이블 및 설명 필드(trData.m_szType, trData.m_szTable 및 trData.m_szDesc)를 채워야 합니다. 마법사가 생성한 예제는 한 행(테이블)만 사용합니다. 다른 공급자는 테이블을 한 개 이상 반환할 수도 있습니다.
CShortNameSessionColSchemaRowset에서 테이블의 이름을 DBID로 전달합니다.
제한 설정
스키마 행 집합 지원의 중요한 개념은 제한을 설정하는 것입니다. 제한은 SetRestrictions를 사용하여 설정합니다. 제한을 설정하면 사용자가 "MyTable"이라는 테이블의 모든 열을 찾은 다음 일치하는 행만 페치할 수 있습니다. 제한은 선택 사항입니다. 제한을 지원하지 않을 경우, 즉 기본값을 사용할 경우에는 모든 데이터가 반환됩니다. 제한을 지원하는 공급자 예제는 UpdatePV 샘플을 참조하십시오.
스키마 맵 설정
UpdatePV의 Session.h에 다음과 같이 스키마 맵을 설정합니다.
BEGIN_SCHEMA_MAP(CUpdateSession)
SCHEMA_ENTRY(DBSCHEMA_TABLES, CUpdateSessionTRSchemaRowset)
SCHEMA_ENTRY(DBSCHEMA_COLUMNS, CUpdateSessionColSchemaRowset)
SCHEMA_ENTRY(DBSCHEMA_PROVIDER_TYPES, CUpdateSessionPTSchemaRowset)
END_SCHEMA_MAP()
IDBSchemaRowset을 지원하려면 DBSCHEMA_TABLES, DBSCHEMA_COLUMNS 및 DBSCHEMA_PROVIDER_TYPES를 지원해야 합니다. 필요하면 다른 스키마 행 집합을 추가할 수 있습니다.
UpdatePV의 CUpdateSessionTRSchemaRowset과 같이 Execute 메서드를 사용하여 스키마 행 집합 클래스를 선언합니다.
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은 IDBSchemaRowsetImpl에서 상속하므로 모든 제한 처리 메서드를 갖고 있습니다. CSchemaRowsetImpl을 사용하여 위의 스키마 맵에 나열된 세 자식 클래스인 CUpdateSessionTRSchemaRowset, CUpdateSessionColSchemaRowset 및 CUpdateSessionPTSchemaRowset을 선언합니다. 각 자식 클래스에는 각각의 제한 집합(검색 조건)을 처리하는 Execute 메서드가 있습니다. 각 Execute 메서드는 cRestrictions와 rgRestrictions 매개 변수의 값을 비교합니다. 이 매개 변수에 대한 설명은 SetRestrictions를 참조하십시오.
특정 스키마 행 집합에 해당하는 제한에 대한 자세한 내용은 Windows SDK의 OLE DB Programmer's Reference에서 IDBSchemaRowset의 스키마 행 집합 GUID 표를 참조하십시오.
예를 들어, DBSCHEMA_TABLES에서 TABLE_NAME 제한을 지원할 경우에는 다음과 같이 하십시오.
먼저 DBSCHEMA_TABLES를 찾은 다음 다음 네 제한을 순서대로 지원하는지 확인합니다.
스키마 행 집합 제한 |
제한 값 |
---|---|
TABLE_CATALOG |
0x1 (이진 1) |
TABLE_SCHEMA |
0x2 (이진 10) |
TABLE_NAME |
0x4 (이진 100) |
TABLE_TYPE |
0x8 (이진 1000) |
그런 다음 각 제한에 대해 1비트씩이 있는지 확인합니다. TABLE_NAME만 지원하기 때문에 rgRestrictions 요소에 0x4를 반환해야 합니다. TABLE_CATALOG와 TABLE_NAME을 지원할 경우에는 0x5 (이진 101)를 반환합니다.
기본적으로 이 구현은 제한을 하나도 지원하지 않기 때문에 모든 요청에 대해 0을 반환합니다. UpdatePV는 제한을 지원하는 공급자 예제입니다.
예제
이 코드는 UpdatePV 샘플에서 가져온 것입니다. UpdatePv는 DBSCHEMA_TABLES, DBSCHEMA_COLUMNS 및 DBSCHEMA_PROVIDER_TYPES의 세 필수 스키마 행 집합을 지원합니다. 공급자에 스키마 지원을 구현하는 방법을 보여 주는 예제인 이 항목에서는 DBSCHEMA_TABLE 행 집합을 구현합니다.
참고: |
---|
샘플 코드와 여기에 있는 코드가 다르면 샘플 코드가 더 최신 버전입니다. |
스키마 지원을 추가하는 첫 번째 단계는 지원할 제한을 결정하는 것입니다. 사용자의 스키마 행 집합에 사용할 수 있는 제한을 결정하려면 OLE DB 사양에서 IDBSchemaRowset 정의 부분을 참조하십시오. 기본 정의를 참조하면 스키마 행 집합 이름, 제한 번호, 제한 열이 포함된 테이블을 볼 수 있습니다. 지원할 스키마 행 집합을 선택하고 제한 번호와 제한 열을 기록합니다. 예를 들어, DBSCHEMA_TABLES는 TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME 및 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;
}
}
비트는 각 제한 열을 나타냅니다. 제한을 지원하려면, 즉 제한을 사용하여 쿼리하려면 비트를 1로 설정하고, 제한을 지원하지 않으려면 0으로 설정합니다. 위의 코드에서 UpdatePV는 DBSCHEMA_TABLES 행 집합에서 TABLE_NAME과 TABLE_TYPE 제한을 지원합니다. 이는 세 번째(비트 마스크 100)와 네 번째(비트 마스크 1000) 제한입니다. 따라서 UpdatePv의 비트 마스크는 1100(또는 0x0C)입니다.
if (InlineIsEqualGUID(rguidSchema[l], DBSCHEMA_TABLES))
rgRestrictions[l] = 0x0C;
다음 Execute 함수는 일반 행 집합의 Execute 함수와 비슷합니다. pcRowsAffected, cRestrictions 및 rgRestrictions의 세 인수가 있습니다. pcRowsAffected 변수는 공급자가 스키마 행 집합에 행 개수를 반환할 수 있는 출력 매개 변수입니다. cRestrictions 매개 변수는 소비자가 공급자에게 전달한 제한 번호가 포함된 입력 매개 변수입니다. rgRestrictions 매개 변수는 제한 값이 포함된 VARIANT 값 배열입니다.
HRESULT Execute(DBROWCOUNT* pcRowsAffected, ULONG cRestrictions,
const VARIANT* rgRestrictions)
cRestrictions 변수는 공급자가 제한을 지원하는지에 관계없이 스키마 행 집합의 총 제한 개수를 기반으로 합니다. UpdatePv는 세 번째와 네 번째 제한을 지원하므로 이 코드는 3보다 크거나 같은 cRestrictions 값만 찾습니다.
TABLE_NAME 제한의 값은 rgRestrictions[2]에 저장됩니다. 0부터 시작하는 배열에서는 세 번째 제한이 2가 됩니다. 실제로 제한을 지원하려면 제한이 VT_EMPTY가 아닌지 확인해야 합니다. VT_NULL은 VT_EMPTY와 다릅니다. VT_NULL은 유효한 제한 값을 지정합니다.
테이블 이름에 대한 UpdatePv 정의는 텍스트 파일에 대한 정규화된 경로 이름입니다. 제한 값을 추출한 다음 파일을 열어 파일이 실제로 있는지 확인합니다. 파일이 없으면 S_OK를 반환합니다. 약간 이상할 수도 있지만 실제로는 지정한 이름이 지원하는 테이블이 없음을 소비자에게 알리는 것입니다. 즉, S_OK가 반환되면 코드가 제대로 실행된 것입니다.
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);
}
}
}
네 번째 제한(TABLE_TYPE)을 지원하는 것은 세 번째 제한을 지원하는 것과 비슷합니다. 값이 VT_EMPTY가 아닌지 확인합니다. 이 제한은 TABLE 테이블 형식만 반환합니다. DBSCHEMA_TABLES에 대한 유효한 값을 확인하려면 TABLES 행 집합 단원에 있는 OLE DB Programmer's Reference의 부록 B를 참조하십시오.
// 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;
}
}
여기에 행 집합에 대한 행 항목을 실제로 만듭니다. trData 변수는 OLE DB 공급자 템플릿에 정의된 구조인 CTABLESRow에 해당합니다. CTABLESRow는 OLE DB 사양의 부록 B에 있는 TABLES 행 집합 정의에 해당합니다. 한 번에 한 테이블만 지원할 수 있으므로 추가할 행을 하나만 갖게 됩니다.
// 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는 TABLE_NAME, TABLE_TYPE 및 DESCRIPTION 세 열만 설정합니다. GetDBStatus를 구현할 때 필요하므로 정보를 반환할 열을 기록해 두어야 합니다.
_ATLTRY
{
m_rgRowData.Add(trData);
}
_ATLCATCHALL()
{
return E_OUTOFMEMORY;
}
//if (!m_rgRowData.Add(trData))
// return E_OUTOFMEMORY;
*pcRowsAffected = 1;
return S_OK;
}
GetDBStatus 함수는 스키마 행 집합이 제대로 작동하도록 하기 위한 아주 중요한 함수입니다. TABLES 행 집합의 모든 열에 데이터를 반환하지는 않기 때문에 데이터를 반환할 열과 반환하지 않을 열을 지정해야 합니다.
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 함수는 TABLES 행 집합의 TABLE_NAME, TABLE_TYPE 및 DESCRIPTION 필드에 대해 데이터를 반환하므로, OLE DB 사양의 부록 B에서 이 필드가 위에서부터 아래로 서수 3, 4, 6임을 확인할 수 있습니다. 이러한 각 열에 대해 DBSTATUS_S_OK를 반환합니다. 나머지 열에 대해서는 DBSTATUS_S_ISNULL을 반환합니다. 소비자는 사용자가 반환한 값이 NULL인지 아니면 다른 값인지를 알 수 없기 때문에 반드시 이 상태를 반환해야 합니다. 여기서도 마찬가지로 NULL은 비어 있는 것과는 다릅니다.
OLE DB 스키마 행 집합 인터페이스에 대한 자세한 내용은 OLE DB Programmer's Reference의 IDBSchemaRowset을 참조하십시오.
소비자가 IDBSchemaRowset 메서드를 사용하는 방법에 대한 자세한 내용은 스키마 행 집합을 사용하여 메타데이터 구하기를 참조하십시오.
스키마 행 집합을 지원하는 공급자 예제는 UpdatePV 샘플을 참조하십시오.