Partager via


Prise en charge des jeux de lignes du schéma

Mise à jour : novembre 2007

Les jeux de lignes du schéma permettent aux consommateurs d'obtenir des informations sur un magasin de données sans connaître sa structure sous-jacente, ou schéma. Par exemple, un magasin de données peut avoir des tables organisées selon une hiérarchie définie par l'utilisateur, de sorte que la seule façon de connaître le schéma est de le lire. (En guise d'exemple supplémentaire, notez que les Assistants Visual C++ utilisent les jeux de lignes du schéma pour générer des accesseurs destinés au consommateur.) Pour permettre au consommateur d'accomplir cette tâche, l'objet session du fournisseur expose les méthodes sur l'interface IDBSchemaRowset. Dans les applications Visual C++, vous utilisez la classe IDBSchemaRowsetImpl pour implémenter IDBSchemaRowset.

IDBSchemaRowsetImpl prend en charge les méthodes suivantes :

  • CheckRestrictions vérifie la validité des restrictions par rapport à un jeu de lignes du schéma.

  • CreateSchemaRowset implémente une fonction du créateur d'objet COM pour l'objet spécifié par le paramètre du modèle.

  • SetRestrictions spécifie les restrictions que vous prenez en charge sur un jeu de lignes particulier du schéma.

  • IDBSchemaRowset::GetRowset retourne un jeu de lignes du schéma (hérité de l'interface).

  • GetSchemas retourne une liste de jeux de lignes du schéma accessible par IDBSchemaRowsetImpl::GetRowset (héritée de l'interface).

Prise en charge de l'Assistant Fournisseur OLE DB ATL

L'Assistant Fournisseur OLE DB ATL crée trois classes de schéma dans le fichier d'en-tête de session :

  • CShortNameSessionTRSchemaRowset

  • CShortNameSessionColSchemaRowset

  • CShortNameSessionPTSchemaRowset

Ces classes répondent aux demandes des consommateurs en matière d'informations sur les schémas ; notez que la spécification OLE DB exige que ces trois jeux de lignes du schéma soient pris en charge :

  • CShortNameSessionTRSchemaRowset gère les demandes d'informations sur la table (le jeu de lignes du schéma DBSCHEMA_TABLES).

  • CShortNameSessionColSchemaRowset gère les demandes d'informations sur les colonnes (le jeu de lignes du schéma DBSCHEMA_COLUMNS). L'Assistant fournit un exemple d'implémentations de ces classes, qui retournent des informations de schéma pour un fournisseur DOS.

  • CShortNameSessionPTSchemaRowset gère les demandes d'informations de schéma concernant le type de fournisseur (le jeu de lignes du schéma DBSCHEMA_PROVIDER_TYPES). L'implémentation par défaut fournie par l'Assistant retourne S_OK.

Vous pouvez personnaliser ces classes pour gérer les informations sur le schéma appropriées à votre fournisseur :

  • Dans CShortNameSessionTRSchemaRowset, vous devez renseigner les champs du catalogue, de la table et de la description (trData.m_szType, trData.m_szTable et trData.m_szDesc). L'exemple généré par l'Assistant utilise une seule ligne (table). D'autres fournisseurs peuvent retourner plusieurs tables.

  • Dans CShortNameSessionColSchemaRowset, vous devez passer le nom de la table en tant que DBID.

Définition des restrictions

Un concept important dans la prise en charge des jeux de lignes du schéma est la définition des restrictions, que vous effectuez à l'aide de SetRestrictions. Les restrictions permettent aux consommateurs d'extraire uniquement les lignes correspondantes (par exemple, rechercher toutes les colonnes dans la table « MyTable »). Les restrictions sont facultatives, et dans le cas où aucune restriction n'est prise en charge (valeur par défaut), toutes les données sont retournées. Pour obtenir un exemple de fournisseur qui prend en charge les restrictions, consultez l'exemple UpdatePV.

Définition du mappage du schéma

Définissez un mappage du schéma comme celui-ci dans Session.h (UpdatePV) :

BEGIN_SCHEMA_MAP(CUpdateSession)
    SCHEMA_ENTRY(DBSCHEMA_TABLES, CUpdateSessionTRSchemaRowset)
    SCHEMA_ENTRY(DBSCHEMA_COLUMNS, CUpdateSessionColSchemaRowset)
    SCHEMA_ENTRY(DBSCHEMA_PROVIDER_TYPES, CUpdateSessionPTSchemaRowset)
END_SCHEMA_MAP()

Pour prendre en charge IDBSchemaRowset, vous devez prendre en charge DBSCHEMA_TABLES, DBSCHEMA_COLUMNS et DBSCHEMA_PROVIDER_TYPES. Vous pouvez ajouter des jeux de lignes du schéma supplémentaires selon vos besoins.

Déclarez une classe de jeu de lignes du schéma à l'aide d'une méthode Execute telle que CUpdateSessionTRSchemaRowset dans 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)

Notez que la classe CUpdateSession hérite de IDBSchemaRowsetImpl, de sorte qu'elle possède toutes les méthodes de gestion des restrictions. Faites appel à CSchemaRowsetImpl pour déclarer trois classes enfant (énumérées dans le mappage du schéma ci-dessus) : CUpdateSessionTRSchemaRowset et CUpdateSessionColSchemaRowset, CUpdateSessionPTSchemaRowset. Chacune de ces classes enfant possède une méthode Execute qui gère son jeu de restrictions respectif (critères de recherche). Chaque méthode Execute compare les valeurs des paramètres cRestrictions et rgRestrictions. Consultez la description de ces paramètres dans SetRestrictions.

Pour plus d'informations sur les restrictions correspondant à un jeu de lignes du schéma particulier, consultez la table des GUID des rowsets du schéma dans IDBSchemaRowset dans le Guide de référence du programmeur OLE DB du Kit de développement logiciel (SDK) Windows.

Par exemple, si vous avez pris en charge la restriction TABLE_NAME sur DBSCHEMA_TABLES, vous devez procéder de la façon suivante :

D'abord, consultez DBSCHEMA_TABLES et vérifiez que ce type prend en charge quatre restrictions (dans l'ordre).

Restriction de jeu de lignes du schéma

Valeur de restriction

TABLE_CATALOG

0x1 (binaire 1)

TABLE_SCHEMA

0x2 (binaire 10)

TABLE_NAME

0x4 (binaire 100)

TABLE_TYPE

0x8 (binaire 1000)

Ensuite, notez qu'à chaque restriction correspond un bit. Dans la mesure où vous voulez prendre en charge TABLE_NAME uniquement, vous devez retourner 0x4 dans l'élément rgRestrictions. Si vous prenez en charge TABLE_CATALOG et TABLE_NAME, vous devrez retourner 0x5 (binaire 101).

Par défaut, l'implémentation retourne 0 (ne prend en charge aucune restriction) pour n'importe quelle demande. UpdatePV est un exemple de fournisseur qui prend en charge les restrictions.

Exemple

Ce code provient de l'exemple UpdatePV. UpdatePv prend en charge les trois jeux de lignes du schéma requis : DBSCHEMA_TABLES, DBSCHEMA_COLUMNS et DBSCHEMA_PROVIDER_TYPES. En tant qu'exemple du mode d'implémentation de la prise en charge du schéma dans votre fournisseur, cette rubrique vous initie à l'implémentation du jeu de lignes DBSCHEMA_TABLE.

Remarque :

Si l'exemple de code et le texte répertorié dans les rubriques suivantes diffèrent, c'est l'exemple de code qui doit être considéré comme étant la version la plus récente.

Lors de l'ajout de la prise en charge du schéma, la première étape consiste à déterminer les restrictions que vous allez prendre en charge. Pour déterminer les restrictions disponibles pour votre jeu de lignes du schéma, examinez la spécification OLE DB pour la définition de IDBSchemaRowset. Après la définition principale, vous allez voir une table contenant le nom du jeu de lignes du schéma, le nombre de restrictions et les colonnes des restrictions. Sélectionnez le jeu de lignes du schéma que vous souhaitez prendre en charge, puis notez le nombre de restrictions et de colonnes des restrictions. Par exemple, DBSCHEMA_TABLES prend en charge quatre restrictions (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME et 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;
   }
}

Chaque colonne de restriction est représentée par un bit. Si vous souhaitez prendre en charge une restriction (c'est-à-dire, l'utiliser comme critère d'interrogation), affectez à ce bit la valeur 1. Dans le cas contraire, affectez à ce bit la valeur zéro. À partir de la ligne de code ci-dessus, UpdatePV prend en charge les restrictions TABLE_NAME et TABLE_TYPE sur le jeu de lignes DBSCHEMA_TABLES. Il s'agit des troisième (masque binaire 100) et quatrième (masque binaire 1000) restrictions. Par conséquent, le masque de bits pour UpdatePv équivaut à 1100 (ou 0x0C) :

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

La fonction Execute suivante est similaire à celles qui figurent dans des jeux de lignes ordinaires. Vous avez trois arguments : pcRowsAffected, cRestrictions et rgRestrictions. La variable pcRowsAffected est un paramètre de sortie permettant au fournisseur de retourner le nombre de lignes dans le jeu de lignes du schéma. Le paramètre cRestrictions est un paramètre d'entrée contenant le nombre de restrictions passées par le consommateur au fournisseur. Le paramètre rgRestrictions est un tableau de valeurs VARIANT contenant les valeurs de restriction.

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

La variable cRestrictions repose sur le nombre total de restrictions pour un jeu de lignes du schéma, que le fournisseur les prenne en charge ou non. Dans la mesure où UpdatePv prend en charge deux restrictions (les troisième et quatrième), ce code recherche uniquement une valeur cRestrictions supérieure ou égale à trois.

La valeur de la restriction TABLE_NAME est stockée dans rgRestrictions[2] (de nouveau, la troisième restriction dans un tableau basé sur zéro est 2). Vous devez vérifier que la restriction est différente de VT_EMPTY pour pouvoir en fait la prendre en charge. Notez que VT_NULL n'est pas égale à VT_EMPTY. VT_NULL spécifie une valeur de restriction valide.

La définition UpdatePv d'un nom de table est un nom de chemin d'accès complet à un fichier texte. Extrayez la valeur de restriction, puis essayez d'ouvrir le fichier afin de vous assurer que le fichier existe réellement. Si le fichier n'existe pas, retournez S_OK. Cela peut sembler être un retour en arrière mais ce que le code indique vraiment au consommateur c'est qu'aucune table portant le nom spécifié n'est prise en charge. Le retour de S_OK signifie que le code a été exécuté correctement.

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);
        }
    }
}

La prise en charge de la quatrième restriction (TABLE_TYPE) est similaire à celle de la troisième restriction. Vérifiez que la valeur est différente de VT_EMPTY. Cette restriction retourne uniquement le type de table, TABLE. Pour déterminer les valeurs valides pour DBSCHEMA_TABLES, consultez l'annexe B du manuel OLE DB Programmer's Reference dans la section du jeu de lignes 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;
    }
}

C'est là où vous créez en fait une entrée de ligne pour le jeu de lignes. La variable trData correspond à CTABLESRow, une structure définie dans les modèles du fournisseur OLE DB. CTABLESRow correspond à la définition du jeu de lignes TABLES dans l'annexe B de la spécification OLE DB. Vous n'avez qu'une ligne à ajouter car vous ne pouvez prendre en charge qu'une table à la fois.

// 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 définit trois colonnes seulement : TABLE_NAME, TABLE_TYPE et DESCRIPTION. Vous devez noter les colonnes pour lesquelles vous retournez des informations, car vous avez besoin de ces informations lors de l'implémentation de GetDBStatus :

    _ATLTRY
    {
        m_rgRowData.Add(trData);
    }
    _ATLCATCHALL()
    {
        return E_OUTOFMEMORY;
    }
    //if (!m_rgRowData.Add(trData))
    //    return E_OUTOFMEMORY;
    *pcRowsAffected = 1;
    return S_OK;
}

La fonction GetDBStatus est très importante pour le fonctionnement correct du jeu de lignes du schéma. Dans la mesure où vous ne retournez pas de données pour chaque colonne dans le jeu de lignes TABLES, vous devez spécifier les colonnes pour lesquelles vous retournez des données et celles pour lesquelles vous ne retournez pas de données.

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;
    }
}

Dans la mesure où la fonction Execute retourne des données pour les champs TABLE_NAME, TABLE_TYPE et DESCRIPTION à partir du jeu de lignes TABLES, vous pouvez consulter l'annexe B de la spécification OLE DB pour déterminer (en effectuant un comptage de haut en bas) qu'il s'agit des ordinaux 3, 4 et 6. Pour chacune de ces colonnes, retournez DBSTATUS_S_OK. Pour toutes les autres colonnes, retournez DBSTATUS_S_ISNULL. Il est important de retourner cet état, car le consommateur peut ne pas comprendre que la valeur que vous retournez est égale à NULL ou à une autre valeur. Notez encore une fois que la valeur NULL ne signifie pas vide.

Pour plus d'informations sur l'interface du jeu de lignes du schéma OLE DB, consultez l'interface IDBSchemaRowset dans le manuel OLE DB Programmer's Reference.

Pour plus d'informations sur la façon dont les consommateurs peuvent utiliser les méthodes IDBSchemaRowset, consultez Récupération de métadonnées à l'aide de jeux de lignes du schéma.

Pour obtenir un exemple de fournisseur qui prend en charge les jeux de lignes du schéma, consultez l'exemple UpdatePV.

Voir aussi

Concepts

Techniques avancées du fournisseur