# 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