MI_DATUM in a C UDR (Server)

In a C UDR, the contents of an MI_DATUM structure depend on the SQL data type of the value, as follows:
  • For most data types, the MI_DATUM structure contains a pointer to the data type.

    The actual value of most data types is too large to fit within an MI_DATUM structure. For such data types, the DataBlade® API passes the value using the pass-by-reference mechanism. Use the contents of the MI_DATUM structure as a pointer to access the actual value.

  • For a few small data types, the MI_DATUM structure contains the actual data value.

    Types of values that fit in an MI_DATUM structure (Passed by value) shows the few data types whose value can always fit in an MI_DATUM structure. For these data types, the DataBlade API passes the value using the pass-by-value mechanism. Use the contents of the MI_DATUM structure as the actual data value.

Table 1. Types of values that fit in an MI_DATUM structure (Passed by value)
DataBlade API data types Length SQL data types
Data types that can hold four-byte integers, including mi_integer and mi_unsigned_integer 4 The SQL INTEGER data type
mi_date 4 The SQL DATE data type
Data types that can hold two-byte integers, including mi_smallint and mi_unsigned_smallint 2 The SQL SMALLINT data type
Data types that can hold a one-byte character, including mi_char1 and mi_unsigned_char1 1 The SQL CHAR(1) data type

(Multicharacter values must be passed by reference.)

mi_boolean 1 The SQL BOOLEAN data type
mi_pointer size of (void *) The SQL POINTER data type
C data structure for the internal format of an opaque data type when the structure size can fit into an MI_DATUM structure Depends on the size of the C data structure An opaque data type whose CREATE OPAQUE TYPE statement specifies the PASSEDBYVALUE modifier
For all data types that Types of values that fit in an MI_DATUM structure (Passed by value) lists, the DataBlade API passes the value in an MI_DATUM structure by value unless the variable is declared as pass by reference. For example, in the following sample function signature, the arg2 variable would be passed by reference to the my_func() UDR because it is declared as a pointer:
mi_integer my_func(arg1, arg2)
   mi_integer arg1; /* passed by value */
   mi_integer *arg2; /* passed by reference */

Values of data types with sizes smaller than or equal to the size of void * can be passed by value because they can fit into an MI_DATUM structure. A value smaller than the size of MI_DATUM is cast promoted to the MI_DATUM size with whatever byte position is appropriate for the computer architecture. When you obtain a smaller passed-by-value value from an MI_DATUM structure, you need to reverse the cast promotion to ensure that your value is correct.

For example, an mi_boolean value is a one-byte value. To pass it by value, the DataBlade API performs something like the following example when it puts the mi_boolean value into an MI_DATUM structure:
datum = (void *((char) bool))

In the preceding cast promotion, datum is an MI_DATUM structure and bool is an mi_boolean value.

When you obtain the mi_boolean value from the MI_DATUM structure, reverse the cast-promotion process with something like the following example:
mi_boolean bool_val;
MI_DATUM datum;
...
bool_val = (char) datum;

To avoid the cast promotion situation, it is recommended that you declare small pass-by-value SQL types as mi_integer.

For all data types not listed in Types of values that fit in an MI_DATUM structure (Passed by value), the DataBlade API passes the value in an MI_DATUM structure by reference; that is, the MI_DATUM structure contains a pointer to the actual data type.
Important: Do not assume that any data type of length 1, 2, or 4 is passed by value. Not all one-, two-, or four-byte datums are passed by value. For example, the mi_real data type is passed by reference. Always check the data type or use the mi_type_byvalue() function to determine the passing mechanism.
UDRs store the data types of their arguments in an MI_FPARAM structure. You can check the type identifier of an argument to determine if it is passed by value or by reference, as the following code fragment shows:
my_type_id = mi_fp_argtype(my_fparam, 1);
my_type_desc = mi_type_typedesc(conn, my_type_id);
if ( mi_type_byvalue(my_type_desc) == MI_TRUE )
   {
   /* Argument is passed by value: extract one-, two-, or 
    * four-byte item from argument
    */
   }
else
   {
   /* Argument is passed by reference: it contains a pointer
    * to the actual value
    */
   }

However, a UDR that hardcodes a type identifier in a switch or if statement to determine actions can handle only built-in data types. It cannot handle all possible user-defined types because not all of them have unique, type-specific identifiers.