When you declare a C UDR, you specify the routine return value, as follows:
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:
|
Data types that can fit into the MI_DATUM structure | Can
return the value by value:
|
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:
Most data types are passed by reference. The sample UDR bigger_double( ), in Figure 67, shows how to return an mi_double_precision value by reference. It allocates PER_ROUTINE memory for the return value, which the database server frees when the user-defined function completes.
For a list of data types that can be returned by value, see Table 13. The sample UDR bigger_int( ), in Figure 68, shows how to return an mi_integer value by 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.
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:
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.
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:
Therefore, a C UDR must declare its return value as a pointer to the internal format of the fixed-length opaque type. Only if the internal format can fit into an MI_DATUM structure can the C UDR pass the internal format by value.
Therefore, a C UDR must declare its return value as a pointer to an mi_bitvarying. To return a varying-length opaque type, the UDR must put the varying-length structure into the data portion of the mi_bitvarying structure and return a pointer to this mi_bitvarying structure.
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.
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.
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:
The size of the OUT parameter must be the size of an MI_DATUM structure. The passing mechanism for the parameter must be pass by reference regardless of the data type that you pass back.
The UDR should update the argument-value array.
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.
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.
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;
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 ]