Example C++ Code - Teradata Meta Data Services

Teradata Meta Data Services Programmer Guide

Teradata Meta Data Services
Release Number
English (United States)
Last Update
Product Category
Teradata Tools and Utilities

Example C++ Code

The following examples assume you have used the "import" MS complier directive to read the MetaCOMExport21 type library, and add any import settings you desire for your own situation. For example, if you have installed MDS in the usual place on the C drive, and wish to use a namespace of "tdmds" rather than "METACOMEXPORT21Lib", you would add the following statement to your code:

#import "C:\Program Files\Teradata\Meta Data Services\bin\metacomexport21.dll" \

From the TLI and TLH files that are generated, you can use the appropriate interface-class smart pointers to declare interface classes, and make the property and method calls on those interfaces.


The following code declares and creates an IMetaActive interface pointer from the MetaActive coclass object. It then makes a call to the Initialize and DeInitialize routines of the IMetaActive interface.

// If you use "using namespace tdmds;" you could drop the scope-resolution
// qualifier "tdmds::" from the code below.
// The IMetaActivePtr "smart pointer" below is defined in the TLH file created
// as a result of the "import" statement.
tdmds::IMetaActivePtr ipRepos;
try {
   HRESULT hr = ipRepos.CreateInstance(__uuidof(tdmds::MetaActive));
   if ( FAILED(hr) ) _com_issue_error(hr);
   ipRepos->Initialize(_bstr_t("metasu"), _bstr_t("metasu"));
   // Other repository actions...
catch(_com_error& e)
   // Handle the COM error...

Read Model Classes and Class Properties

The following routine demonstrates a way to enumerate through a Model's Classes and the Properties for each Class. We assume that the "import" statement shown above appears before this routine and that this is an MFC application. Note that the two "while" loops are effectively the equivalent of the Visual Basic "for-each" loop. The Initialize/DeInitialize calls would probably be done at the application level.

using namespace tdmds;
HRESULT ClassesAndProperties(LPCTSTR strModelName) {
				// All the IMeta*Ptr variables below are smart pointers created by the
	// #import statement (in the *.tli or *.tlh files).
   IMetaActivePtr ipMetaAct;
   IMetaModelInfoPtr ipModel;
   // MDS COM Collections next:
   IMetaClassInfoListPtr ipClassList;
   IMetaPropertyInfoPtr ipPropInfo;
   HRESULT hr = S_OK;
        CString msg;
        hr = ipMetaAct.CreateInstance(__uuidof(MetaActive));
        if ( FAILED(hr) ) throw(hr);
        hr = ipModel.CreateInstance(__uuidof(MetaModelInfo));
        if ( FAILED(hr) ) throw(hr);
        // Initialize first
        ipMetaAct->Initialize(_T("metasu"), _T("metasu"));
        // If this were an IMetaInfo object, we would need more than just the name,
        // but since this is an IMetaModelInfo, the Name is enough.
        // The VARIANT_TRUE parameter requests
        // that the Relationships and Classes be read also.
        // Get the Classes for this model in our Class-list (interface) variable.
        ipClassList = ipModel->GetClassList();
        if ( ipClassList->GetCount() )
              _variant_t var;
              IEnumVARIANT* ipClsEnum = NULL;
              IUnknownPtr ipClsUnk;
              ipClsUnk = ipClassList->Get_NewEnum();
              CString msgCls;
              msg.Format("Classes for meta-model <%s>:\n",
              hr = ipClsUnk->QueryInterface(&ipClsEnum);
              while ( ipClsEnum->Next(1, &var, NULL) != S_FALSE )
                   IMetaClassInfoPtr ipClsInfo;
                   ipClsInfo = var;
                   CString classMsg;
                   // Get the class info and Property list for this class
                   _bstr_t aimClass = ipClsInfo->GetName();
                   long clsID = ipClsInfo->GetObjectID();
                   classMsg.Format("%s [%d]\n", (LPCTSTR)aimClass, clsID);
                   IMetaPropertyInfoListPtr ipPropertyList;
                   ipPropertyList = ipClsInfo->GetPropertyList();
                   long cntProp;
                   cntProp = ipPropertyList->GetCount();
                   if ( cntProp )
                        // Can iterate thru via GetItem() or VB-style NewEnum()
                        _variant_t var;
                        IEnumVARIANT* ipEnum = NULL;
                        IUnknownPtr ipPropUnk;
                        classMsg += " Properties :\n";
                        ipPropUnk = ipPropertyList->Get_NewEnum();
                        hr = ipPropUnk->QueryInterface(&ipEnum);
                        while ( ipEnum->Next(1, &var, NULL) != S_FALSE )
                             ipPropInfo = var;
                             CString propMsg;
                             _bstr_t propName(ipPropInfo->GetName());
                             long id = ipPropInfo->GetIdentifier();
                             propMsg.Format(" %s [%d]\n",
                                              (LPCTSTR)propName, id);
                             classMsg += propMsg;
        // Can DeInit now if desired
    catch(HRESULT hr)
         // Handle HRESULT error...
    catch(const _com_error& e)
         // Display _com_error...
         CString errMsg;
         errMsg.Format(_T("COM call FAILED: %s [0x%X]\n"), (LPCTSTR)e.Description(),
         hr = e.Error();
    return hr;

Add a User or Group to a Security Profile

The following routine updates a user or group access type for a Security Profile. If the user/group is not already in the permission list, it will be added. Note that the GetObjectID call does NOT throw an error if the object id requested is not found, it simply returns 0. As usual, we assume the "import" statement appears somewhere before this code. The Initialize/DeInitialize calls would probably be done at the application level.

using namespace tdmds;
HRESULT UpdateSecProfileAccessType (
                  LPCTSTR ugName, // Name of the User/Group to update
                  AccessType access, // (New) Access type of the user/group
                  bool bUser, // true for user, false for group
                  LPCTSTR spName // Name of the SecProfile to update
   HRESULT hr = S_OK;
   long idUG;
   long idSP;
   try {
        IMetaActivePtr ipRepos(__uuidof(MetaActive));
        // Initialize with the Repository.
        ipRepos->Initialize(L"metasu", L"metasu");
        // Get the Class ID for the user / group -- these are in metaglobals.h
        long idCls = bUser ? CLSLOID_UserClass : CLSLOID_ApplicationGroupClass;
        // Get User / Group Object ID
        idUG = ipRepos->GetObjectID(L"", L"", idCls, ugName);
        if ( idUG == 0 ) {
              ::AfxMessageBox("User/Group not in the Repository");
        // Get the SecProfile Object ID -- the SecProf CLSLOID is in metaglobals.h
        idSP = ipRepos->GetObjectID(L"", L"",
                          CLSLOID_SecurityProfileClass, spName);
        if ( idSP == 0 ) {
              ::AfxMessageBox("Security Profile not in the Repository");
        // Create the Security Profile and SP Entry objects
        IMetaSecProfEntryPtr ipSPE(__uuidof(MetaSecProfEntry));
        IMetaSecProfInfoPtr ipSP(__uuidof(MetaSecProfInfo));
        // Set the values for the entry will we will be updating below.
        ipSPE->SetEntryValues(IsUser, idUG, access);
        // Read in our Sec Prof., update the entry in its permission list,
        // and Write it back out to the Repository.
        // Can DeInit now if desired
  catch(const _com_error& e)
        // Display _com_error...
        CString errMsg;
        errMsg.Format(_T("COM call FAILED: %s [0x%X]\n"), (LPCTSTR)e.Description(),