Prise en charge des ensembles de lignes de schéma
Les ensembles de lignes de schéma permettent au consommateur d’obtenir des informations sur une banque de données sans connaître sa structure sous-jacente ou son schéma. Par exemple, une banque de données peut contenir des tableaux organisés selon une hiérarchie définie par l’utilisateur, il n’y aurait donc aucun moyen de connaître le schéma à moins de le lire. (Comme autre exemple, les Assistants Visual C++ utilisent des ensembles de lignes de schéma pour générer des accesseurs pour le consommateur.) Pour permettre au consommateur de procéder ainsi, l’objet de session du fournisseur expose des 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 ensemble de lignes de schéma.
CreateSchemaRowset implémente une fonction de créateur d’objet COM pour l’objet spécifié par le paramètre du modèle.
SetRestrictions spécifie les restrictions prises en charge sur un ensemble de lignes de schéma en particulier.
IDBSchemaRowset::GetRowset retourne un ensemble de lignes de schéma (hérité de l’interface).
GetSchemas retourne une liste d’ensembles de lignes de schéma accessibles 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 n’est pas disponible dans Visual Studio 2019 et versions ultérieures.
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 requêtes de consommateur concernant les informations sur le schéma. Notez que la spécification OLE DB requiert que ces trois ensembles de lignes de schéma soient pris en charge :
CShortNameSessionTRSchemaRowset gère les requêtes d’informations sur les tableaux (l’ensemble de lignes de schéma DBSCHEMA_TABLES).
CShortNameSessionTRSchemaRowset gère les requêtes d’informations sur les tableaux (l’ensemble de lignes de schéma DBSCHEMA_TABLES). L’Assistant fournit des exemples d’implémentation de ces classes, qui retournent des informations de schéma pour un fournisseur de DOS.
CShortNameSessionPTSchemaRowset gère les demandes d’informations de schéma sur le type de fournisseur (l’ensemble 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 de schéma adaptées à votre fournisseur :
Dans CShortNameSessionTRSchemaRowset, vous devez remplir les champs du catalogue, du tableau et de la description (
trData.m_szType
,trData.m_szTable
, ettrData.m_szDesc
). L’exemple généré par l’Assistant n’utilise qu’une seule ligne (tableau). D’autres fournisseurs peuvent retourner plusieurs tableaux.Dans CShortNameSessionColSchemaRowset, vous passez le nom du tableau en tant que
DBID
.
Définition des restrictions
La définition des restrictions est un concept important dans la prise en charge des ensembles de lignes de schéma. Vous l’effectuez à l’aide de SetRestrictions
. Les restrictions permettent aux consommateurs de récupérer uniquement les lignes correspondantes (par exemple, toutes les colonnes de la table « MaTable »). Les restrictions sont facultatives, et dans le cas où aucune n’est prise en charge (par défaut), toutes les données sont systématiquement retournées. Pour obtenir un exemple de fournisseur qui prend en charge les restrictions, consultez l’exemple UpdatePV.
Configuration du mappage de schéma
Configurez un mappage de schéma similaire à celui-ci dans Session.h dans 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 ensembles de lignes de schéma supplémentaires comme bon vous semble.
Déclarez une classe d’ensemble de lignes de schéma avec 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)
CUpdateSession
hérite de IDBSchemaRowsetImpl
et dispose donc de toutes les méthodes de gestion des restrictions. À l’aide de CSchemaRowsetImpl
, déclarez les trois classes enfants (répertoriées dans le mappage du schéma ci-dessus) : CUpdateSessionTRSchemaRowset
, CUpdateSessionColSchemaRowset
, et CUpdateSessionPTSchemaRowset
. Chacune de ces classes enfants dispose d’une méthode Execute
qui gère son ensemble de restrictions (critères de recherche) respectif. 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 ensemble de lignes de schéma spécifique, consultez le tableau des GUID d’ensemble de lignes de schéma dans IDBSchemaRowset dans les Informations de référence du programmeur OLE DB du SDK Windows.
Par exemple, si vous avez pris en charge la restriction TABLE_NAME sur DBSCHEMA_TABLES, effectuez ce qui suit :
Tout d’abord, consultez DBSCHEMA_TABLES et vérifiez s’il prend en charge quatre restrictions (dans l’ordre).
Restriction d’ensemble de lignes de schéma | Valeur de restriction |
---|---|
TABLE_CATALOG | 0x1 (1 en binaire) |
TABLE_SCHEMA | 0x2 (10 en binaire) |
TABLE_NAME | 0x4 (100 en binaire) |
TABLE_TYPE | 0x8 (1000 en binaire) |
Ensuite, il y a un bit pour chaque restriction. Étant donné que vous souhaitez prendre en charge TABLE_NAME uniquement, vous retournerez 0x4 dans l’élément rgRestrictions
. Si vous preniez en charge TABLE_CATALOG et TABLE_NAME, vous retourneriez 0x5 (101 en binaire).
Par défaut, l’implémentation retourne 0 (aucune restriction prise en charge) pour toutes les requêtes. UpdatePV constitue un exemple de fournisseur qui prend en charge les restrictions.
Exemple
Le code suivant est extrait de l’exemple UpdatePV. UpdatePv
prend en charge les trois ensembles de lignes de schéma requis : DBSCHEMA_TABLES, DBSCHEMA_COLUMNS et DBSCHEMA_PROVIDER_TYPES. Pour illustrer comment implémenter la prise en charge du schéma dans votre fournisseur, cette rubrique passe en revue l’implémentation de l’ensemble de lignes DBSCHEMA_TABLE.
Remarque
L’exemple de code peut différer de ce qui est répertorié ici. Considérez cet exemple de code comme la version la plus récente.
La première étape de l’ajout de la prise en charge du schéma consiste à décider des restrictions que vous allez prendre en charge. Pour déterminer les restrictions disponibles pour votre ensemble de lignes de schéma, consultez la spécification OLE DB pour la définition de IDBSchemaRowset
. Après la définition principale, vous trouverez un tableau contenant le nom de l’ensemble de lignes de schéma, le nombre de restrictions et les colonnes de restriction. Sélectionnez l’ensemble de lignes de schéma que vous souhaitez prendre en charge et notez le nombre de restrictions et les colonnes de restriction. 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;
}
}
Un bit représente chaque colonne de restriction. Si vous souhaitez prendre en charge une restriction (c’est-à-dire, pouvoir envoyer une requête par cette restriction), définissez ce bit sur 1. Si vous ne souhaitez pas prendre en charge une restriction, définissez ce bit sur zéro. À partir de la ligne de code ci-dessus, UpdatePV
prend en charge les restrictions TABLE_NAME et TABLE_TYPE sur l’ensemble de lignes DBSCHEMA_TABLES. Il s’agit de la troisième (masque de bits 100) et de la quatrième (masque de bits 1000) restriction. Par conséquent, le masque de bits pour UpdatePv
est 1100 (ou 0x0C) :
if (InlineIsEqualGUID(rguidSchema[l], DBSCHEMA_TABLES))
rgRestrictions[l] = 0x0C;
La fonction Execute
suivante est similaire à celles des ensembles de lignes ordinaires. Vous avez trois arguments : pcRowsAffected, cRestrictions, et rgRestrictions. La variable pcRowsAffected est un paramètre de sortie permettant au fournisseur de renvoyer le nombre de lignes de l’ensemble de lignes de schéma. Le paramètre cRestrictions est un paramètre d’entrée qui contient 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 est basée sur le nombre total de restrictions pour un ensemble de lignes de schéma, indépendamment du fait que le fournisseur les prenne en charge ou non. Étant donné que UpdatePv prend en charge deux restrictions (la troisième et la 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] (là encore, la troisième restriction dans un tableau de base zéro est 2). Vérifiez que la restriction n’est pas VT_EMPTY pour pouvoir réellement le prendre en charge. Notez que VT_NULL n’est pas égal à VT_EMPTY. VT_NULL spécifie une valeur de restriction valide.
La définition UpdatePv
d’un nom de tableau est le nom de chemin d’accès complet d’un fichier texte. Extrayez la valeur de restriction et puis essayez d’ouvrir le fichier pour vous assurer que le fichier existe réellement. Si le fichier n’existe pas, retournez S_OK. Cela peut sembler un peu simpliste mais le code indique réellement au consommateur qu’il n’y a aucun tableau pris en charge par le nom spécifié. La valeur de retour S_OK signifie que le code s’est 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 à la restriction de la troisième. Vérifiez que la valeur n’est pas VT_EMPTY. Cette restriction retourne uniquement le type de tableau, TABLE. Pour déterminer les valeurs valides pour DBSCHEMA_TABLES, regardez l’Annexe B des Informations de référence du programmeur OLE DB, dans la section d’ensemble 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 ici que vous créez une entrée de ligne pour l’ensemble de lignes. La variable trData
correspond à CTABLESRow
, une structure définie dans les modèles du fournisseur OLE DB. CTABLESRow
correspond à la définition de l’ensemble de lignes TABLES dans l’Annexe B de la spécification OLE DB. Vous n’avez qu’une ligne à ajouter, car vous pouvez prendre uniquement en charge un seul tableau à 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 seulement trois colonnes : TABLE_NAME, TABLE_TYPE et DESCRIPTION. Prenez note des colonnes pour lesquelles vous retournez des informations, car ces informations sont nécessaires lorsque vous implémentez 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 importante pour le bon fonctionnement de l’ensemble de lignes de schéma. Étant donné que vous ne renvoyez pas les données pour chaque colonne dans l’ensemble de lignes TABLES, vous devez spécifier les colonnes pour lesquelles vous retournez ou non des 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;
}
}
Étant donné que votre fonction Execute
retourne des données pour les champs TABLE_NAME, TABLE_TYPE et DESCRIPTION de l’ensemble de lignes TABLES, vous pouvez rechercher dans l’Annexe B de la spécification OLE DB et déterminer (en comptant du haut vers le bas) qu’ils correspondent aux 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 un consommateur pourrait ne pas comprendre que la valeur que vous retournez est NULL ou autre chose. Là encore, notez que NULL n’est pas équivalent à vide.
Pour plus d’informations sur l’interface d’ensemble de lignes de schéma OLE DB, consultez l’interface IDBSchemaRowset dans les Informations de référence du programmeur OLE DB.
Pour plus d’informations sur la façon dont les utilisateurs peuvent utiliser les méthodesIDBSchemaRowset
, consultez Récupération de métadonnées avec les ensembles de lignes de schéma.
Pour obtenir un exemple de fournisseur qui prend en charge les ensembles de lignes de schéma, consultez l’exemple UpdatePV .