UDA Registry

UDA Registry

Before using any of the registry functions, the application must allocate space for the meta-dictionary structure and initialize the allocated buffer with the mco_metadict_init() API. Because an application may use more than one database, the meta-dictionary is necessary to contain a header and entry for each database dictionary. The size of the buffer should be obtained via the mco_metadict_size() function which returns the size of the meta-dictionary in bytes (including the header).

     
    void mco_metadict_size( unsigned short n_entries, unsigned int * size );
     
    typedef struct tag_mco_metadict_header_t_ 
    {
        unsigned short n_maxentries; /* The maximum number of database
        * dictonaries*/
        unsigned short n_allocated;  /* The current number of registered
        * dictionaries */
    } mco_metadict_header_t;
     
    typedef struct tag_mco_metadict_entry_t_ 
    {
        unsigned short dict_no;   /* dictionary number (starting with 0) */
        unsigned short flags;     /* internal flag */
        char           name[16];  /* dictionary name */
        void         * dict;      /* internal pointer */
        void         * user_data; /* application data */
    } mco_metadict_entry_t;
     

Now, the mco_metadict_init() function can be called to initialize the meta-dictionary. It must be called before any of the UDA API functions are called.

     
    MCO_RET mco_metadict_init ( mco_metadict_header_t * metadict,
                    unsigned int size,
                    unsigned int flags );
     

The application needs to allocate the memory buffer and pass the pointer to the buffer along with its size to the mco_metadict_init() function. The database runtime will determine the maximum number of databases that can be registered within the metadictionary. The application can access this number through the metadict->n_maxentries field.

Note that the mcouda libarary does not allocate any dynamic memory. Therefore, any memory buffers used by the UDA API are allocated by the application. The buffer can either be declared statically or allocated on the heap. Descriptors are often allocated on the application’s stack.

 

When databases are created in conventional memory (as opposed to shared memory), the runtime automatically registers (records) all opened databases in the meta-dictionary. The dictionary name in the meta-dictionary is assigned the database name.

The flags parameter defines what happens during the initialization of the dictionary. Currently the only supported value is:

     
    MCO_METADICT_DONT_LOAD_EXISTING_DBS
     

This flag indicates that the automatic registration of opened databases is not done.

The following API function registers a database dictionary in the meta-dictionary:

     
    MCO_RET mco_metadict_register ( mco_metadict_header_t * metadict,
                        const char * name,
                        const void * dict,
                        const void * user_data );
                         

Note that mco_metadict_init() automatically registers open conventional memory databases. If the database has been opened after the meta-dictionary had been initialized, it can be registered with the mco_metadict_register() API. It is possible to register database dictionaries before opening the database, or without opening the database (for example, the application might need to just receive the specific schema (dictionary) information).

 

It is also possible to register the database dictionary of the current database connection in the meta-dictionary automatically using the following API:

     
    MCO_RET mco_metadict_register_conn( mco_metadict_header_t * metadict,
                        const mco_db_h connection,
                        const void * user_data );
     

Unlike function mco_metadict_register() this function does not require a pointer to a dictionary structure generated by mcocomp. So it is ideal for applications where the database dictionary is not initially known, for example when an application opens a database already created by another application in shared memory.

Another use case of function mco_metadict_register_conn() is an application that uses SQL dynamic DDL operations like create table, alter table etc. Since the database table is created or modified by SQL DDL operations it is impossible to use any statically defined data access functions; i.e. the functions generated by mcocomp. But it is possible to register such a dictionary in the meta-dictionary and then use the UDA API to access its data. Of course it is necessary to register a dictionary again each time that it is modified. The return code MCO_E_SCHEMA_CHANGED is returned by function mco_trans_start() whenever an SQL operation has changed a database schema. In this case the current connection should be closed and then re-connected again; the newly obtained connection should then be used to register its dictionary in the meta-dictionary.

To unregister unused dictionary entries in the meta-dictionary the following function is provided:

     
    MCO_RET mco_metadict_unregister( mco_metadict_header_t * metadict,
                        const char *name);
     

This function marks the specified dictionary entry as empty. Once the meta-dictionary is registered, the following API function can be called to get the count of databases registered:

 
    MCO_RET  mco_metadict_count ( const mco_metadict_header_t * metadict,
                    /* out */ unsigned short * count );
                     

As unregistering a dictionary from the meta-dictionary is possible it must be taken into account when querying the dictionaries array. So it is important to keep the original order of dictionary entries registered in meta-dictionary. For this reason function mco_metadict_unregister() just marks a dictionary entry as empty. Function mco_metadict_count() returns the total count of allocated entries in the meta-dictionary. If dictionary unregister operations were used then it is necessary to check the value returned by function mco_metadict_entry() which indicates whether a dictionary with the specified number actually exists. For example, the following code snippet demonstrates how a loop through entries in a meta-dictionary could be implemented:

     
    /* Get total number of registered dictionaries and print out info for each */
    mco_metadict_count(metadict, &count);
     
    for (dict_no = 0; dict_no < count; ++dict_no) 
    {
        MCO_RET rc;
        mco_metadict_entry_t *entry;
         
        /* Get dictionary by number and check if it is registered */
        rc = mco_metadict_entry(metadict, dict_no, &entry);
         
        if (MCO_E_UDA_DICT_NOTFOUND == rc)
            continue;
         
        /* Process metadictionary entry */
        ...
    }
     

Note that the line if (rc == MCO_E_UDA_NOTFOUND) continue; skips previously unregistered dictionary entries.

There are API functions to get a pointer to the dictionary based on its number, name, or connection handle:

     
    MCO_RET mco_metadict_entry( const mco_metadict_header_t * metadict,
                    unsigned short dict_no,
                    /* out */ mco_metadict_entry_t ** entry );
     
    MCO_RET mco_metadict_entry_name( const mco_metadict_header_t * metadict, 
                        const char * name,
                        /* out */ mco_metadict_entry_t ** entry );
     
    MCO_RET mco_metadict_entry_conn( const mco_metadict_header_t * metadict,
                        const mco_db_h connection,
                        /* OUT */ mco_metadict_entry_t ** entry );
     

The count of structures/classes for a database dictionary can be obtained by:

 
    MCO_RET mco_dict_struct_count( const mco_metadict_header_t * metadict,
                        unsigned short dict_no,
                        /* out */ unsigned short * count );
     

And a pointer to the structure/class based on its number or name by:

     
    MCO_RET mco_dict_struct( const mco_metadict_header_t * metadict,
                    unsigned short dict_no,
                    unsigned short struct_no,
                    /* out */ mco_dict_struct_info_p struct_info );
     
    MCO_RET mco_dict_struct_name( const mco_metadict_header_t * metadict,
                        unsigned short dict_no,
                        const char * name,
                        /* out */ mco_dict_struct_info_p struct_info );