UDA Sequence Support

To support fields of type sequence, three flags are accepted in mco_dict_field_info_t::flags :

 
    #define MCO_DICT_FI_ASC_SEQUENCE       0x100
    #define MCO_DICT_FI_DESC_SEQUENCE      0x200
    #define MCO_DICT_FI_SEQUENCE           0x400
     

If the field type is defined as sequence the mco_dict_field() and mco_dict_field_name() functions set MCO_DICT_FI_SEQUENCE for it. If the sequence is monotonic additionally either MCO_DICT_FI_DESC_SEQUENCE or MCO_DICT_FI_ASC_SEQUENCE is set. A new mco_uda_seq_values_t structure allows retrieving and updating sequence elements:

 
    typedef struct tag_mco_uda_seq_values_t_ 
    {
        mco_size_t      size;
        mco_dict_type_t elem_type;
        uint2           elem_size; /* for MCO_DD_CHAR */
        union 
        {
            mco_uint1       *u1;
            mco_uint2       *u2;
            mco_uint4       *u4;
            mco_uint8       *u8;
            mco_int1        *i1;
            mco_int2        *i2;
            mco_int4        *i4;
            mco_int8        *i8;
            #ifdef MCO_TARGET_FLOAT_SUPPORTED
                float           *f;
                double          *d;
            #endif
            char            *c;
        } v;
    } mco_uda_seq_values_t;
     

Here size is the number of elements in the structure elem_type - the sequence element type - which can be one of the following:

     
    MCO_DD_UINT1, MCO_DD_UINT2, MCO_DD_UINT4, MCO_DD_UINT8,
    MCO_DD_INT1, MCO_DD_INT2, MCO_DD_INT4, MCO_DD_INT8,
    MCO_DD_FLOAT, MCO_DD_DOUBLE or MCO_DD_CHAR
     

Note that elem_size - the element size - only makes sense for the elem_type == MCO_DD_CHAR.

The union element v -references arrays of the corresponding types (the type is defined by the elem_type). The arrays must be allocated and deallocated by the application

The function mco_uda_is_sequence() can be called to determine if a field is of type sequence:

 
    mco_bool mco_uda_is_sequence(mco_dict_type_t type); 
     

This function returns MCO_YES, if the field is defined as a sequence type (i.e. MCO_DD_SEQUENCE_UINT1, MCO_DD_SEQUENCE_FLOAT, etc.).

 

Sequence Functions

The sequence wrapper functions correspond to the function generated by the DDL compiler for sequences, such as:

 
    MCO_RET mco_uda_seq_first(const mco_uda_object_handle_p obj, 
                    unsigned short field_no,/*OUT*/ 
                    mco_uda_value_t *value);
     
    MCO_RET mco_uda_seq_last(const mco_uda_object_handle_p obj, 
                    unsigned short field_no,/*OUT*/ 
                    mco_uda_value_t *value);
     
    MCO_RET mco_uda_seq_append(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_uda_seq_values_t *values);
                     
    MCO_RET mco_uda_seq_insert(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_no_t pos, 
                    mco_uda_seq_values_t *values);
     
    MCO_RET mco_uda_seq_delete(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_no_t from, 
                    mco_seq_no_t till);
     
    MCO_RET mco_uda_seq_count(const mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_no_t *count);
                     
    MCO_RET mco_uda_seq_search(const mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_iterator_h iterator, 
                    const mco_uda_value_t *low, 
                    mco_seq_boundary_kind_t low_boundary, 
                    const mco_uda_value_t *high, 
                    mco_seq_boundary_kind_t high_boundary);
                     
    MCO_RET mco_uda_seq_join(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_iterator_h result, 
                    mco_seq_iterator_h join_with);
                     
    MCO_RET mco_uda_seq_obj_map(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_iterator_h dst_iterator, 
                    mco_seq_iterator_h map_iterator);
 
    MCO_RET mco_uda_seq_subseq(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_iterator_h iterator, 
                    mco_seq_no_t from, 
                    mco_seq_no_t till);
                     
    MCO_RET mco_uda_seq_iterator(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_iterator_h iterator);
                     
    MCO_RET mco_uda_seq_project(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_iterator_h dst, 
                    mco_seq_iterator_h src);
                     
    MCO_RET mco_uda_seq_store(mco_uda_object_handle_p obj, 
                    unsigned short field_no, 
                    mco_seq_iterator_h src);
 
    MCO_RET mco_uda_seq_truncate(const mco_uda_object_handle_p udaobj, 
                    unsigned short field_no);
     

Each mco_uda_seq_<operation>(const mco_uda_object_handle_p obj, unsigned short field_no, ...) function corresponds to the generated <classname>_<fieldname>_<operation>(<classname> *obj, ...). Instead of the type-aware parameters the general mco_uda_value_t structure is used.

For example if the schema defines a sequence field as sequence<float>, then

 
    MCO_RET mco_uda_seq_first(const mco_uda_object_handle_p obj, 
                unsigned short field_no,
                /*OUT*/ mco_uda_value_t *value);
     

corresponds to

     
    MCO_RET Classname_fieldname_first(Classname *handle, float* val);
     

One small exclusion from the naming convention is the <classname>_<fieldname>_map(...) function. It is called mco_uda_seq_obj_map(...). (This is to avoid a conflict with the iterator API below.)

Example Usage:

The following code snippet demonstrates how a sequence of values can be appended to a database object:

 
    mco_uda_seq_values_t seqvals;
    seqvals.elem_type = MCO_DD_UINT4;
    seqvals.size = seq_size;
    seqvals.v.u4 = malloc(sizeof(uint4) * seqvals.size);
    for (i = 0; i < seqvals.size; ++i) 
    {
        seqvals.v.u4[i] = <...>;
    }
    mco_uda_seq_append(&obj, timestamp_no, &seqvals);
    free(seqvals.v.u4);
     

Iterator API

Overall instead of the elements' mco_seq_<operation>_<type>(...) function (such as mco_seq_add_float(), mco_seq_add_uint1() , etc.,) the UDA defines mco_uda_seq_<operation>(). For example mco_uda_seq_add(). Note that the value for the <type> is determined according to the elements' type (if possible). Instead of the type-specific arguments the mco_uda_value_t is used. For example instead of the function

     
    MCO_RET mco_seq_next_uint1(mco_seq_iterator_h iterator, uint1 *val);
     

The UDA APi defines

     
    MCO_RET mco_uda_seq_next(mco_seq_iterator_h iterator, mco_uda_value_t* uda_val);
     

The later function assigns MCO_DD_UINT1 to the uda_val and returns the element in the uda_val->v.u1;

Similarly instead of the arrays of the type-specific values the UDA API uses the generic mco_uda_seq_values_t structure. For example instead of

 
    MCO_RET mco_seq_get_float(mco_seq_iterator_h input, float *result, mco_size_t *size);
     

use

 
    MCO_RET mco_uda_seq_get(mco_seq_iterator_h input, mco_uda_seq_values_t *values);
     

The values.size argument takes the place of the size, and values.v.f is the result.

Overall, the UDA API consists of over a hundred different functions. The entire list can be found in file include/mcouda.h.

Example Usage:

The following example code adds the values of two sequences:

 
    mco_seq_iterator_t result, it1, it2, cast_it2;
     
    mco_uda_seq_iterator(&obj, field1_no, &it1); // get iterator for object's field field1
    mco_uda_seq_iterator(&obj, field2_no, &it2); // get iterator for object's field field2
    mco_uda_seq_cast(&cast_it2, it1.elem_type, &it2); // cast elements from field2 to field1's type
    mco_uda_seq_add(&result, &it1, &cast_it2); // add elements of field1 and field2