Column values passed back to a C UDR (Server)

Within a C UDR, the value buffer that mi_value() or mi_value_by_name() fills can contain either of the following values:
  • For data types that are passed by value, the value buffer contains the actual column value.
  • For data types that are passed by reference, the value buffer contains a pointer to this column value.
Tip: The value buffer also contains a pointer to the column value if the return status of mi_value() or mi_value_by_name() is MI_ROW_VALUE or MI_COLLECTION_VALUE.

Therefore, within your C UDR, you cannot assume what the MI_DATUM value contains without checking its data type (or length).

If the mi_value() or mi_value_by_name() function passes back a value smaller than the size of an MI_DATUM structure, the DataBlade® API cast promotes the smaller value to the size of MI_DATUM. If you now want to pass a pointer in the MI_DATUM structure, you might have problems on Windows™ if you passed the address of the MI_DATUM value, as the following code fragment shows:
MI_DATUM datum;
mi_integer length;
mi_char bool;
mi_short small;
mi_int large;
void *pointer;

switch ( mi_value( ..., &datum, &length ) )
   {
   ....
   } /* end switch */
/* Assume that 'datum' contains a BOOLEAN value 
 * (which uses only one byte of the MI_DATUM storage space). 
 * Pass the address of the actual data to another function.
 * YOU CANNOT ALWAYS DO THIS! 
 *         my_func( &datum, length ); 
 * This address might point to the wrong byte! */

The preceding code fragment works if datum always contains a pointer to a column value or contains data the size of MI_DATUM. It might not work on some computer architectures, however, for data that is smaller than MI_DATUM (such as mi_boolean).

To convert the MI_DATUM value into a pointer to the data value, you must be sure that the address points to the starting position of the cast-promoted data. The following code fragment determines what the MI_DATUM value in datum contains and then correctly copies the value and obtains its address, based on the length of datum:
MI_ROW_DESC *row_desc;
MI_ROW *row;
MI_DATUM datum;
mi_integer length;
mi_boolean *bool;
mi_smallint *small_int;
mi_integer *full_int;
mi_date *date_val;
mi_string *col_type_name;
void *ptr_to_value;
...
switch ( mi_value(row, i, col_id, &datum, &length) )
   {
   ...
   case MI_NORMAL_VALUE:
      col_type_name =
         mi_type_typename(
            mi_column_typedesc(row_desc, i));

/* To obtain the datum value and its address, first check
 * if the value is passed by value. If not, assume that
 * the value is passed by reference.
 */
      switch( length )
         {
      /*  Case 1: Assume that a length of one byte means
       *          that 'datum' contains a BOOLEAN value.
       */
         case 1:
            bool = (mi_boolean) datum;
            ptr_to_value = &bool;
            break;

      /*  Case 2: Assume that a length of two bytes means
       *          that 'datum' contains a SMALLINT value
       */
         case 2:
            small_int = (mi_smallint) datum;
            ptr_to_value = &small_int;
            break;

      /*  Case 4: Assume that a length of four bytes means
       *          that 'datum' contains an INTEGER or DATE value
       */
         case 4:
            if ( stcopy(col_type_name, "date") == 0 )
               {
               date_val = (mi_date) datum;
               ptr_to_value = &date_val;
               }
            else /* data type is INTEGER */
               {
               full_int = (mi_integer) datum;
               ptr_to_value = &full_int;
               }
            break;

      /*  Default Case: Assume that any for any other lengths,
       *                'datum' contains a pointer to the value.
       */
         default:
            ptr_to_value = &datum;
            break;
   } /* end switch */

my_func( ptr_to_value );

The preceding code fragment handles only built-in data types that are passed by value. It was not written to handle all possible user-defined types (such as small fixed-length opaque types) because these do not have unique lengths.

In a C UDR, if the data type of the column value can fit into an MI_DATUM structure, the value buffer contains the actual column value. If you know the data types of the column values, the value buffers you declare to hold the column values must be declared as pointers to their data type. For example, the code fragment declares the value buffer that holds a SMALLINT value can be declared as follows:
mi_integer *small_int_ptr;
After the call to mi_value(), the C UDR must cast the contents of the value buffer from a pointer variable (as small_int_ptr is declared) to the actual data type. For the SMALLINT value, the code can perform the following cast to create a copy of the column value:
small_int = (mi_smallint) small_int_ptr;

This cast is necessary only for column values whose data types are passed by value because the MI_DATUM structure contains the actual column value, not a pointer to the value.

You can use the mi_type_byvalue() function to determine the passing mechanism of the column value that mi_value() passes back, as the following code fragment shows:
row_desc = mi_get_row_desc_without_row(conn);
...
switch ( mi_value(row, i, col_id, &datum, &length) )
   {
   ...
   case MI_NORMAL_VALUE:

      if ( mi_type_byname(mi_column_typedesc(row_desc, i))
            == MI_TRUE )
         {
         /* handle pass-by-value data types */;

The mi_type_byvalue() function helps to determine if a one-, two-, or four-byte value is actually passed by value. You can use this function to determine the passing mechanism of a fixed-length opaque data type.