共用方式為


支援結構描述資料列集

結構描述資料列集可讓消費者取得資料存放區的相關資訊,而不需要知道其基礎結構或結構描述。 例如,資料存放區可能會將資料表組織成使用者定義的階層,因此除了讀取結構描述之外,沒辦法確保知道結構描述 (另一個範例是,Visual C++精靈會使用架構數據列集來產生取用者的存取子。若要允許取用者這樣做,提供者的會話物件會在IDBSchemaRowset介面上公開方法。 在 Visual C++ 應用程式中,您可以使用 IDBSchemaRowsetImpl 類別實作 IDBSchemaRowset

IDBSchemaRowsetImpl 支援下列方法:

  • CheckRestrictions 會針對結構描述資料列集檢查限制的有效性。

  • CreateSchemaRowset 會為範本參數所指定的物件實作 COM 物件建立者函式。

  • SetRestrictions 會指定您在特定結構描述資料列集上支援的限制。

  • IDBSchemaRowset::GetRowset 會傳回 (繼承自介面的) 結構描述資料列集。

  • GetSchemas 會傳回一份可供 (繼承自介面的) IDBSchemaRowsetImpl::GetRowset 存取的結構描述資料列集清單。

ATL OLE DB 提供者精靈支援

Visual Studio 2019 及更新版本中未提供 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_szTypetrData.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 中使用 Execute 方法宣告結構描述資料列集類別,例如 CUpdateSessionTRSchemaRowset

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 宣告三個子類別 (列在上述的結構描述對應中):CUpdateSessionTRSchemaRowsetCUpdateSessionColSchemaRowsetCUpdateSessionPTSchemaRowset。 這些子類別中的每一個都有一個 Execute,可處理其個別一組限制 (搜尋條件)。 每個 Execute 方法都會比較 cRestrictionsrgRestrictions 參數的值。 請參閱 SetRestrictions 中這些參數的描述。

如需對應至特定結構描述資料列集之限制的詳細資訊,請參閱 Windows SDK 之 OLE DB 程式設計人員參考中的 IDBSchemaRowset

例如,如果您支援 DBSCHEMA_TABLES 中的 TABLE_NAME 限制,您會執行下列項目:

首先,查閱 DBSCHEMA_TABLES,並查看它是否支援四個限制 (依順序)。

結構描述資料列集限制 限制值
TABLE_CATALOG 0x1 (二進位 1)
TABLE_SCHEMA 0x2 (二進位 10)
TABLE_NAME 0x4 (二進位 100)
TABLE_TYPE 0x8 (二進位 1000)

接著,每個限制都有一個位元。 因為您只想要支援 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。 如果您不想要支援限制,請將該位元設定為零。 從上面一行程式碼,UpdatePV 在 DBSCHEMA_TABLES 資料列集上支援 TABLE_NAME 和 TABLE_TYPE 限制。 這些是第三個 (位元遮罩 100) 第四個 (位元遮罩 1000) 限制。 因此,UpdatePv 的位元遮罩為 1100 (或 0x0C):

if (InlineIsEqualGUID(rguidSchema[l], DBSCHEMA_TABLES))
    rgRestrictions[l] = 0x0C;

下列 Execute 函式類似於一般的資料列集。 您有三個引數:pcRowsAffectedcRestrictionsrgRestrictionspcRowsAffected 變數是一個輸出參數,可讓提供者在結構描述資料列中傳回資料列計數。 cRestrictions 參數是一個輸入參數,可保存消費者傳遞給提供者的限制數目。 rgRestrictions 參數是 VARIANT 值的一個陣列,可保存限制值。

HRESULT Execute(DBROWCOUNT* pcRowsAffected, ULONG cRestrictions,
                const VARIANT* rgRestrictions)

cRestrictions 變數是以結構描述資料列集的限制總數為基礎,而不管提供者是否支援這些限制。 UpdatePv 支援兩個限制 (第三個和第四個),因此這個程式碼只會尋找大於或等於 3 的 cRestrictions 值。

TABLE_NAME 限制的值會儲存在 rgRestrictions [2] 中 (再次提醒,在以零為基礎的陣列中,第三個限制為 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 的有效值,請查閱 OLE DB 程式設計人員參考附錄 B 中的 TABLES 資料列集一節。

// 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 會對應至 CTABLESRow,這是在 OLE DB 提供者範本中定義的結構。 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 程式設計人員參考中的 IDBSchemaRowset 介面。

如需有關消費者如何使用 IDBSchemaRowset 方法的資訊,請參閱使用結構描述資料列集取得中繼資料

如需支援結構描述資料列集之提供者的範例,請參閱 UpdatePV 範例。

另請參閱

進階的提供者技術