# UDA Object Interfaces

> To allocate a new database object call the following API function:

>         MCO_RET mco_uda_new( mco_trans_h t,
>                     unsigned short struct_no,
>                     const void * oid,
>                     const mco_uda_value_t * initializers,
>                     unsigned short initializers_no,
>                     /* out */ mco_uda_object_handle_t * obj );

> To remove an object from the database call the following API function:

>         MCO_RET mco_uda_delete ( mco_uda_object_handle_t * obj );

> To cause an object’s indexes to be created before the transaction in which it is instantiated or updated is commited, call the following API function:

>         MCO_RET mco_uda_checkpoint  ( mco_uda_object_handle_t * obj );

> ## Put / Get Functions

> To assign the field value for an object or structure use:

>         MCO_RET mco_uda_put( mco_uda_object_handle_p obj,
>                     unsigned short field_no,
>                     unsigned short index,
>                     const mco_uda_value_p value );

> In order to assign the value, the application sets the field type in `value->type`. The type must correspond to the DDL type:

> - for simple types, assign the value (`value->v.u1`, `value->v.u2`, etc)
> - for strings, arrays and blobs, set the appropriate pointer to reference the value (`value->v.p.p.c`, `value->v.p.p.n` or `value->v.p.p.v`) and put the size of the value into `v.p.len`
> - for structure-based fields (`MCO_DD_STRUCT`), use `mco_uda_put()` to initialize the descriptor `v.o`; Use the descriptor as the first parameter passed to `mco_uda_put()`

> Example

>         mco_uda_object_handle_t obj;
>         MCO_RET rc;
>         mco_uda_value_t v;
>         ...
>         rc = mco_uda_new( t, Rec_class_no,
>                      0 /* no oid */,
>                     0 /* no init.*/,
>                      0,
>                      &obj);

>                 v.type = MCO_DD_UINT4;
>                 v.v.u4 = 100;
>                 rc = mco_uda_put( &obj, uint4_field_no, 0, &v );
>                 v.type = MCO_DD_STRING;
>                 v.v.p.len = 5;
>                 v.v.p.p.c = "Hello";
>                 rc = mco_uda_put( &obj, string_field_no, 0, &v );
>                 v.type = MCO_DD_BLOB;
>                 v.v.p.len = blob_size;
>                 v.v.p.p.v = blob_value;

>         rc = mco_uda_put( &obj, blob_field_no, 0, &v );

> To get the value of an object’s field:

>         MCO_RET mco_uda_get ( const mco_uda_object_handle_p obj,
>                     unsigned short field_no,
>                     unsigned short index,
>                     /* out */ mco_uda_value_t * val );

> Note that for simple types (integers, float, double) the field value is returned in the corresponding `mco_uda_value_t` structure field.

> For strings, byte arrays, and blobs, the application needs to allocate a buffer and pass it into the API:

> `val->v.p.p.c` – `MCO_DD_CHAR` or `MCO_DD_STRING`

> `val->v.p.p.n` – `MCO_DD_NCHAR_CHAR` or `MCO_DD_NCHAR_STRING`

> `val->v.p.p.v` – `MCO_DD_BLOB` or `MCO_DD_REF`

> In addition, `val->v.p.size` must hold the size of the buffer (in bytes).

> The function copies the field value into the buffer and also returns the actual number of symbols (bytes for blobs) copied in `val->v.p.len`.

> It is possible to use the `mco_uda_get()` function to receive the size of the buffer in advance. If the pointer (`val->v.p.p.c`, `val->v.p.p.n` or `val->v.p.p.v`) is set to zero, the API just fills out the `val.v.p.size`, and does not copy the actual value into the buffer.

> For structure-based fields (`MCO_DD_STRUCT`), the API fills out `val->v.o`, that can be used to further pass it into the `mco_uda_get()` and gain access to the structure fields.

> Example 1

>         mco_uda_value_t val;
>         val.type = MCO_DD_STRING;
>         val.v.p.p.c = 0; /* figure out the actual size we need to allocate
>         */
>         mco_uda_get(&obj, my_field_no, 0, &val);
>         val.v.p.p.c = malloc(val.v.p.size);
>         mco_uda_get(&obj, field_no, 0, &val); /* get the value */
>         ....<whatever processing is necessary>
>         free(val.v.p.p.c); /* free up memory */

> Example 2 (strings)

>         mco_uda_value_t val;
>         val.type = MCO_DD_STRING;
>         val.v.p.p.c = 0;
>         mco_uda_get(&obj, my_field_no, 0, &val);
>         val.v.p.size += sizeof(char);
>         val.v.p.p.c = malloc(val.v.p.size ); /* field value size */
>         ....<processing results>
>         free(val.v.p.p.c); /* */

> Example 3 (Unicode strings)

>         mco_uda_value_t val;
>         val.type = MCO_DD_NCHAR_STRING;
>         val.v.p.p.c = 0;
>         mco_uda_get(&obj, my_field_no, 0, &val);
>         val.v.p.size += sizeof(nchar);
>         val.v.p.p.c = malloc(val.v.p.size );
>         mco_uda_get(&obj, field_no, 0, &val);
>         ....<processing results>
>         free(val.v.p.p.c);

> Note that `mco_uda_get()` can return `MCO_S_NULL_VALUE`, in which case nothing is copied to the output parameter.

> Note that null indicator fields are just normal fields, identified by:

> >         #define MCO_DICT_FI_NULL_INDICATOR      0x80  /* field is null indicator */

> > Accordingly, to set (or clear) a `nullable` field to (from) `null`, use `mco_uda_put()` on the appropriate `null` indicator field. Indicator field names (`mco_dict_field_info_t.name`) are the name of the base field appended with “`_indicator`”. The following code snippet illustrates how to retrieve the field info for an indicator field’s base field:

> >         if (field_info.flags & MCO_DICT_FI_NULL_INDICATOR)
> >          {
> >             char nullable_fldname[MAX_NAME_LEN];
> >             mco_dict_field_info_t nullable_field_info;
> >             strcpy(nullable_fldname, field_info.name);
> >             nullable_fldname[strlen(nullable_fldname) - strlen("_indicator")] = '\0';
> >             mco_dict_field_name(metadict, dict_no, struct_no, nullable_fldname,
> >             &nullable_field_info);
> >             ...
> >         }

> To update blob fields it may be more convenient to call the following append API rather than loading the entire blob and then rewriting it:

>         MCO_RET mco_uda_blob_append (
>             /*IN*/ mco_uda_object_handle_p obj,
>             /*IN*/ unsigned short field_no,
>             /*IN*/ const void *value,
>             /*IN*/ uint4 size);

> Example 4 (Append to blob)

>         mco_uda_object_handle_t obj;
>         MCO_RET rc;
>         mco_uda_value_t v;
>         void *append_value;
>         uint4 append_size;
>         ...
>         rc = mco_uda_new( t, Rec_class_no, 0 /* no oid */,0 /* no init.*/, 0, &obj);
>         v.type = MCO_DD_BLOB;
>         v.v.p.len = blob_size;
>         v.v.p.p.v = blob_value;
>         rc = mco_uda_put( &obj, blob_field_no, 0, &v );
>         ...
>         rc = mco_uda_blob_append( &obj, blob_field_no, append_value, append_size);