UDA User Defined Indexes

User Defined Indexes

User-defined indexes for the eXtremeDB native API are explained in the Indexes and Cursors page. As with native User-defined Functions (udf) the UDA API requires that the application supply two compare functions for tree indexes and two additional hash functions for hash indexes. For tree indexes, provide one custom function that compares two objects and one that compares an object to an external key value. For hash indexes, provide two pairs of functions: two returning a hash code and two compare functions (if a user-defined tree index is also defined then these compare functions are used for the hash index as well).

These functions must then be registered with the runtime before cursor functions can be called on these indexes by passing a parameter of the following type:

     
    typedef struct mco_uda_userdef_funcs_t_ 
    {
        mco_uda_compare_userdef_f         fcomp;
        mco_uda_compare_extkey_userdef_f  fcomp_ext;
        mco_uda_hash_userdef_f            fhash;
        mco_uda_hash_extkey_userdef_f     fhash_ext;
    } mco_uda_userdef_funcs_t, *mco_uda_userdef_funcs_h;
     

The application implements these compare functions with the following function signatures:

 
    /* Object - Object */
    typedef int2(*mco_uda_compare_userdef_f)( mco_uda_object_handle_p obj1,
                            unsigned short index1,
                            mco_uda_object_handle_p obj2,
                            unsigned short index2,
                            void *user_context);
     
    /* Object - external key(s) */
    typedef int2(*mco_uda_compare_extkey_userdef_f)( mco_uda_object_handle_p obj,
                                unsigned short index,
                                mco_uda_value_t *keys,
                                uint2 keys_count,
                                void *user_context);
                                 
     

These compare functions must return <0, =, or >0 depending on whether the object value is less than, equal to or greater than the external key value.

In addition, for hash indexes, two custom functions need be implemented with the following function signatures:

     
    /* Hash - Object */
    typedef uint4 (*mco_uda_hash_userdef_f)( mco_uda_object_handle_p obj,
                        unsigned short index,
                        void *user_context);
     
    /* Hash – external key(s) */
    typedef uint4 (*mco_uda_hash_extkey_userdef_f)( mco_uda_value_t *keys,
                            uint2 keys_count,
                            void *user_context);
     

Note that hash index compare functions return 0 if and only if two objects (or object and external key) are equal from the index point of view. This is necessary for hash index operations because hash codes may be equal yet the objects (keys) are not. When mco_uda_lookup() is called with a hash index, it will call the user-defined compare function to assure that any matching hash code actually exactly matches the indexed database field value.

Notice also that the compare functions receive application specific data passed from the caller via the user_context parameter.

In addition to the compare functions, the UDA API requires a udf map for the internal implementation of index navigation. This udf map must be allocated and passed to the runtime when the udfs are registered.

The following function queries the database dictionary to determine the amount of memory to be allocated for the udf map:

     
    MCO_RET mco_uda_get_udfmap_size( const mco_metadict_header_t * metadict,
                        unsigned short dict_no,
                        /* out */ unsigned int * size);
     

Once the compare functions are defined, the mco_uda_userdef_funcs_t structure initialized, and the udf map allocated and its size determined, use the following API to register the udfs with the runtime:

     
    MCO_RET mco_uda_register_udf( const mco_metadict_header_t * metadict,
                    unsigned short dict_no,
                    unsigned short struct_no,
                    unsigned short index_no,
                    mco_userdef_funcs_h udf_map,
                    mco_uda_userdef_funcs_h udf_entry,
                    void *user_context);
     

The following code snippet demonstrates how to register udf compare functions:

 
    /* allocate udfmap */
    mco_uda_get_udfmap_size(metadict, 0, &udf_map_size);
     
    udf_map = (mco_userdef_funcs_h) malloc(udf_map_size);
     
    /* register user-defined compare & hash functions */
    udf_entry.fcomp     = cmp_obj_obj;  /* Object – object compare */
    udf_entry.fcomp_ext = cmp_obj_ext;  /* Object – key compare */
    udf_entry.fhash     = hash_obj;     /* Hash – object compare */
    udf_entry.fhash_ext = hash_ext;     /* Hash – key compare */
    param.fld_no = name_no; /* will pass name_no to compare/hash functions */
     
    rc = mco_uda_register_udf( metadict,
                     0,
                     Record_no,
                     tudf_no,
                     udf_map,
                    &udf_entry,
                     (void*) &param);
                     
    if ( MCO_S_OK != rc) 
    {
        printf("Error in mco_uda_register_udf() : %s\n", mco_ret_string(rc, 0));
        exit(0);
    }
     

Note that the user-context parameter param is used by the external key compare functions to call mco_uda_get() to retrieve the database field value to be compared to the external key value.

 

The registration API must be called for all user-defined indexes, before the application makes a call to mco_db_connect().

Note that for shared-memory databases, the udf functions must be registered in each process separately.