Home | Previous Page | Next Page   Creating User-Defined Routines > Writing a User-Defined Routine > Coding a C UDR >

Defining a Return Value

When you declare a C UDR, you specify the routine return value, as follows:

Important:
A C user-defined function can only return one value.

Returning a Value

When a user-defined function completes, the routine manager returns its value as an MI_DATUM value. The data type of the return value determines the passing mechanism that the routine manager uses for the value, as follows:

The passing mechanism that the routine manager uses for a particular return value determines how you must declare it in the user-defined function, as follows.

Return-Value Data Type Tasks to Return the Value
Data types that cannot fit into an MI_DATUM structure Return the value by reference:
  • Declare a local variable that is a pointer to the actual return value
  • Allocate the memory for the return value with the PER_ROUTINE memory duration. Use a DataBlade API memory-management function. For more information, see Managing User Memory.
  • Assign the address of this memory to a local variable
  • Store the return value in this memory
  • Return the pointer to this memory as the return value
Data types that can fit into the MI_DATUM structure Can return the value by value:
  • Declare a local variable to hold the actual return value
  • Store the return value in this local variable
  • Return the local variable as the return value

Important:
A user-defined function cannot return an automatic or local variable if its data type cannot be returned by value. That is, any automatic or local variables with data types that cannot fit into an MI_DATUM structure cannot be returned by value from the UDR.

To return a value, use the automatic or local variable that you declared in the user-defined function, like you would any other C-function variable, as follows:

Tip:
You can obtain information about a return value, such as its type or maximum length, from the MI_FPARAM structure. For more information, see Accessing Return-Value Information.
Returning a NULL Value

To return an SQL NULL value from a user-defined function, pass the MI_FPARAM structure as the last argument in the UDR and use the mi_fp_setreturnisnull( ) function to set the NULL value in this MI_FPARAM structure. You must call the mi_fp_setreturnisnull( ) function with MI_TRUE before your UDR completes. If you do not, you might receive an incorrect result from the UDR. Do not just return a NULL-valued pointer. For more information, see Returning a NULL Value.

Returning Character Values

The routine manager handles all character return values from a C UDR as mi_lvarchar values. Therefore, a C UDR must declare its return value as a pointer to an mi_lvarchar when it returns data for any of the following SQL character data types:

Note:
Use of the SQL TEXT data type in a C UDR is not supported.
Global Language Support

For more information on the NCHAR and NVARCHAR data types, see the IBM Informix: GLS User's Guide.

End of Global Language Support
Important:
SQL data types are not represented as null-terminated strings, so do not code a C UDR to return a null-terminated string. For more information on how to access an mi_lvarchar structure, see Varying-Length Data Type Structures.

For example, the initial_cap( ) function in Figure 69 can ensure that names are entered with an initial uppercase letter followed by lowercase letters. This UDR would be useful in the following query to ensure consistent capitalization of the customer last name:

INSERT INTO customer(customer_num, lname, fname)
VALUES (0, initial_cap("ANDERSON"), initial_cap("TASHI"));

The calls to initial_cap( ) in this INSERT statement convert the last and first names of this customer as Anderson and Tashi, respectively.

Figure 69 shows the following declaration for initial_cap( ):

/* Valid C UDR declaration for string return value */
mi_lvarchar *initial_cap(str)
   mi_lvarchar *str;

This declaration correctly specifies an mi_lvarchar pointer as the return type so that the function can return the VARCHAR value. The following declaration of initial_cap( ) is invalid because it specifies an mi_string pointer as the return type:

/* INVALID declaration for string return value */
mi_string *initial_cap(string)
   mi_lvarchar *string;

The initial_cap( ) function in the preceding declaration would not return the expected value because the routine manager interprets the mi_string that the UDR returns as an mi_lvarchar.

Tip:
A C UDR that accepts data for one of these SQL character data types must also declare its parameters as mi_lvarchar pointers. For more information, see Handling Character Arguments.
Returning Opaque-Type Values

When the routine manager returns opaque-type data from a C UDR, the way it handles the return value depends on the kind of opaque data type, as follows:

Tip:
A C UDR that accepts opaque-type data must also declare its parameters based on whether the opaque type is fixed-length or varying-length. For more information, see Handling Opaque-Type Arguments.

Returning Multiple Values

Unlike an SPL routine, a C user-defined function can directly return at most one value. However, a user-defined function can return multiple values when you use the following features together:

OUT parameters and SLVs enable a user-defined function to return a second value to the calling SQL statement.

Tip:
This section discusses the use of SLVs and OUT parameters in the context of a C user-defined function. You cannot use SLVs and OUT parameters in SPL functions. A user-defined procedure with an OUT parameter must be called in the WHERE clause of an SQL statement. For general information on how to use an OUT parameter, see the discussion of how to return multiple values from external functions in the IBM Informix: User-Defined Routines and Data Types Developer's Guide.

An alternative to using an OUT parameter is an iterator function. This special-purpose user-defined function can return multiple values, one value per iteration of the function. For more information, see Writing an Iterator Function.

Using an OUT Parameter

An OUT parameter is a routine argument that is always passed by reference to the C user-defined function. A C user-defined function can use an OUT parameter to return a value indirectly. For the OUT parameter, the database server allocates storage for an opaque data type or for a data type that you could pass by value (but not for a varying-length data type) and passes a pointer to that storage to the UDR. Multiple OUT parameters are supported and they are allowed anywhere in the argument list, not just at the end.

For a C user-defined function to receive an OUT parameter, it must perform the following actions:

DataBlade API modules often use OUT parameters for Boolean functions to return rank or scoring information (which can indicate how closely the return result matched the query criteria). For example, Figure 72 shows a C UDR, named out_test( ), that does not actually search a particular title for a string, but returns a 100 percent relative weight of match success as an OUT parameter.

Figure 72. The out_test( ) User-Defined Function
mi_integer out_test(
   mi_lvarchar *doc,
   mi_lvarchar *query,
   mi_integer *weight,    /* OUT parameter */
   MI_FPARAM *fp)
{
   /* Set the value of the OUT parameter */
   *weight = 100;

   /* Set the value of the OUT parameter to "not null" */
   mi_fp_setargisnull(fp, 2, MI_FALSE);

   return MI_TRUE;
}

In Figure 72, the call to the mi_fp_setargisnull( ) function sets the third argument, which is the OUT parameter, to MI_FALSE, which indicates that the argument does not contain an SQL NULL value. The MI_FPARAM structure stores routine arguments in zero-based arrays. Therefore, the mi_fp_setargisnull( ) function specifies a position of 2 to access the third argument.

Tip:
For more information on how to access the MI_FPARAM structure, see Accessing MI_FPARAM Routine-State Information.

When you register the user-defined function, precede the OUT parameter with the OUT keyword. For example, the following CREATE FUNCTION statement registers the out_test( ) function (which is defined in Figure 72):

CREATE FUNCTION out_test(doc LVARCHAR, 
                  query VARCHAR(120), 
                  OUT weight INTEGER)
   RETURNING BOOLEAN
   EXTERNAL NAME '/usr/udrs/udrs.so'
   LANGUAGE C;
Using the Statement-Local Variable

When you call a user-defined function that has an OUT parameter, you must declare a statement-local variable (SLV) in the WHERE clause of the SQL statement. The SLV holds the value that the OUT parameter returns. Other parts of the SQL statement can then access the OUT parameter value through the SLV.

For example, the following SELECT statement calls the out_test( ) function (which Figure 72 defines) and saves the result of the OUT parameter in a statement-local variable named weight:

SELECT title, weight FROM mytab
   WHERE out_test(title, 'aaa', weight # INTEGER);

The SELECT statement specifies the statement-local variable in its select list so it can return the value of the OUT parameter.

For more information on the syntax and use of SLVs, see the description of how to return multiple values from a function in the IBM Informix: User-Defined Routines and Data Types Developer's Guide.

Home | [ Top of Page | Previous Page | Next Page | Contents | Index ]