informix
Informix DataBlade API Programmer's Manual
Executing User-Defined Routines

Calling UDRs with the Fastpath Interface

The DataBlade API Fastpath interface allows DataBlade API modules to directly invoke a UDR that was registered in the database without the overhead of parsing, planning, and executing an SQL statement. This interface bypasses the query optimizer and executor (which are needed for an SQL statement). You can use this interface to execute both C UDRs and SPL routines.

Important: You cannot use the Fastpath interface to execute iterator functions or SPL functions with the WITH RESUME keywords in their RETURN statement. For more information on iterator functions, see Writing an Iterator Function.

Situations in which the Fastpath interface is useful for calling a UDR include the following:

The Fastpath interface looks up a UDR or cast function in the system catalog tables to obtain information about the routine and then executes it. It passes any return values from the routine to the caller in internal (binary) format. With the Fastpath interface, a DataBlade API module can call a foreign UDR.

For a C UDR, a foreign UDR is a UDR that does not reside in the same shared-object file as the UDR that calls it. One UDR can only call another UDR directly when that called UDR resides within the same shared-object file or DataBlade module as the calling UDR. For example, in Figure 9-9 on page 9-21, the func3() user-defined function can directly call func2() because both of these functions reside in the source1.so shared-object file.

However, there is no portable way for the C code in one shared-object file to directly call a function in another shared-object file. Different operating systems provide different degrees of support for this type of calling. In addition, if the foreign UDR is part of a DataBlade module, your UDR has no way of knowing which DataBlade modules might be installed at a particular customer site.

To call a foreign UDR, a C UDR must use the DataBlade API Fastpath interface. Figure 9-10 shows how a UDR that is one shared-object file, source1.so, can call a foreign user-defined routine, funcB(). Even though the funcB() routine is defined in the source2.so shared-object file, func3() can invoke it through the Fastpath interface.

Figure 9-10
Using Fastpath to Access a Routine in Another
Shared-Object File

In Figure 9-10, the Fastpath interface loads the source2.so shared-object file, which contains the funcB() routine, into memory. For Fastpath to be able to invoke funcB(), the funcB() routine must already have been registered in the database. Notice that the call to funcB() within funcC() does not require use of the Fastpath interface, because these two functions resides in the same shared-object file, source2.so.

The Fastpath interface allows a DataBlade developer to extend a DataBlade module that someone else provides. This developer can define new UDRs on data types that some other DataBlade provides.

For a client LIBMI application, a foreign UDR is any UDR that is registered in the database that is currently open. Client LIBMI programs can use the Fastpath interface to directly invoke registered UDRs.

You can execute foreign UDRs with an SQL statement, such as EXECUTE FUNCTION. (For more information, see Calling UDRs Within a DataBlade API Module.) However, Fastpath is usually a quicker method for the execution of a UDR because it bypasses query processing.

Important: For the Fastpath interface to execute a UDR, the UDR must be registered in the database with a CREATE FUNCTION or CREATE PROCEDURE statement. When you create a DataBlade, register internal UDRs that might be of general use. In this way, you can cleanly protect private interfaces and support public ones.

The Fastpath interface provides the following DataBlade API functions to look up a registered UDR, execute it, and free resources.

DataBlade API Function Purpose For More Information
Look up a UDR and obtain a function descriptor for it: page 9-26
mi_cast_get() Looks up a cast function that casts between two data types (specified by type identifiers) and returns its function descriptor.
mi_func_desc_by_typeid() Looks up a user-defined routine by its routine identifier and returns its function descriptor.
mi_routine_get() Looks up a user-defined routine by its routine signature (specified as a character string) and returns its function descriptor.
mi_routine_get_by_typeid() Looks up a user-defined routine by its routine signature (specified as separate arguments) and returns its function descriptor.
mi_td_cast_get() Looks up a cast function that casts between two data types (specified by type descriptors) and returns its function descriptor.
Obtain information from a function descriptor: page 9-35
mi_fparam_get() Returns a pointer to the MI_FPARAM structure that is associated with the function descriptor.
mi_func_handlesnulls() Determines whether the UDR that is associated with the function descriptor can handle NULL arguments.
mi_func_isvariant() Determines whether the user-defined function that is associated with the function descriptor is a variant function.
mi_func_negator() Determines whether the user-defined function that is associated with the function descriptor has a negator function.
mi_routine_id_get() Returns the routine identifier for the routine that is associated with the function descriptor.
Execute the UDR through its function descriptor: page 9-39
mi_routine_exec() function.
Use a user-allocated MI_FPARAM structure for the UDR: page 9-46
mi_fparam_allocate() Allocate an MI_FPARAM structure.
mi_fparam_copy() Create a copy of an existing MI_FPARAM structure
mi_fparam_free() Deallocate a user-allocated MI_FPARAM structure
mi_fp_usr_fparam() Determine whether a specified MI_FPARAM has been allocated by the database server or the user.
Free resources that the function descriptor uses: page 9-50
mi_routine_end() Releases resources that are associated with the function descriptor.

The following sections describe each of these steps in more detail.

Obtaining a Function Descriptor

A function descriptor, MI_FUNC_DESC, contains static information about a user-defined routine that is to be invoked with the Fastpath interface. It is basically a structured version of the row in the sysprocedures system catalog table that describes the UDR. The function descriptor also identifies the routine sequence for the associated user-defined routine. (For more information on the routine sequence, see Creating the Routine Sequence.)

The following table summarizes the memory operations for a function descriptor.

Default Memory Duration Memory Operation Function Name
PER_COMMAND Constructor mi_cast_get(), mi_func_desc_by_typeid(), mi_routine_get(), mi_routine_get_by_typeid(), mi_td_cast_get()
Destructor mi_routine_end()

A calling DataBlade API module uses a function descriptor as a handle to identify the UDR it needs to invoke with the Fastpath interface. To obtain a function descriptor, you call a Fastpath look-up function that looks up one of the following types of UDR in the sysprocedures table:

Looking Up User-Defined Routines

To look up a user-defined routine, use one of the following Fastpath look-up functions.

DataBlade API Function How It Looks Up a User-Defined Routine
mi_routine_get() Looks up a user-defined routine by a routine signature that is passed as a character string.
mi_routine_get_by_typeid() Looks up a user-defined routine by a routine signature that is passed as separate arguments.
mi_func_desc_by_typeid() Looks up a user-defined routine by its routine identifier.

The mi_func_desc_by_typeid() function is only available within a C UDR. It is not valid within a client LIBMI application.

These Fastpath look-up functions perform the following steps:

  1. Ask the database server to look up the user-defined routine in the sysprocedures system catalog.
  2. If the name of the user-defined routine in the routine signature that you specify is not unique in the database, the mi_routine_get() and mi_routine_get_by_typeid() functions use the routine signature to perform routine resolution. For more information, see Routine Resolution.

    The routine identifier uniquely identifies a UDR. Therefore, the mi_func_desc_by_typeid() function does not need to perform routine resolution.

  3. Allocate a function descriptor for the routine and save the routine sequence in this descriptor.
  4. You can obtain information about the UDR from this function descriptor. For more information, see Obtaining Information from a Function Descriptor. You can also allocate your own MI_FPARAM structure to use instead of this automatically allocated one. For more information, see Using a User-Allocated MI_FPARAM Structure.

  5. Allocate an MI_FPARAM structure for the function descriptor.
  6. You can get a pointer to this structure with the mi_fparam_get() function. For more information, see Obtaining the MI_FPARAM Structure.

  7. Return a pointer to the function descriptor that has been allocated for the user-defined routine.
  8. Subsequent calls to mi_routine_exec() can use this function descriptor to identify the user-defined routine to execute. For more information, see Executing the Routine.

    Tip: The mi_routine_get(), mi_routine_get_by_typeid(), and mi_func_desc_by_typeid() functions search for user-defined routines only in the sysprocedures system catalog table. Therefore, these functions can locate only registered user-defined functions (which CREATE FUNCTION registers) and user-defined procedures (which CREATE PROCEDURE registers).

Suppose the following CREATE FUNCTION statements register three user-defined functions called numeric_func() in your database:

The numeric_func() user-defined function is an overloaded routine. The code fragment in Figure 9-11 uses the mi_routine_get() function to obtain the function descriptor for the version of numeric_func() that handles INTEGER arguments.

Figure 9-11
Obtaining a Function Descriptor for the numeric_func() Function

The mi_routine_get() function returns a NULL-valued pointer to indicate either no matching routine exists or the routine has multiple return values. Figure 9-11 also shows how to determine which of these conditions a NULL return value indicates. It uses the mi_fparam_get() function to obtain the MI_FPARAM structure that is associated with the located numeric_func() function. (The mi_routine_get() function has allocated and initialized this MI_FPARAM structure as part of the look-up process.) The code fragment then uses the mi_fp_nrets() accessor function to obtain the number of UDR return values from this MI_FPARAM structure. Because C UDRs can only return one value, any UDR that returns more than one value must be an SPL routine.

Use mi_routine_get() when you can create the full signature of the UDR as a literal string. Otherwise, you can use the mi_routine_get_by_typeids() function to build the routine signature. For example, if you have a user-supplied query, you could use mi_column_typeid() to get the type identifier for the column that the query returns. The mi_routine_get_by_typedesc() function is also useful when you need to invoke overloaded UDRs with different parameter data types (and you have parameter type identifiers).

In Figure 9-11, you could replace the call to mi_routine_get() with the following call to the mi_routine_get_by_typeid() function:

In this call to mi_routine_get_by_typeid(), the arg_types array contains pointers to the type identifiers for the two INTEGER parameters.

If you already have a routine identifier for the UDR that you want to execute with Fastpath, use the mi_func_desc_by_typeid() function to obtain its function descriptor. In Figure 9-11, you could replace the call to mi_routine_get() with the following call to mi_func_desc_by_typeid():

In this call, the mi_funcid data type holds the routine identifier of the UDR to look up.

When you call mi_routine_get() or mi_routine_get_by_typeid() from a client LIBMI application, the function allocates a local copy (on the client computer) of the function descriptor and MI_FPARAM structure. You can use the function-descriptor and MI_FPARAM accessor functions within a client LIBMI application to access these local copies.

The mi_func_desc_by_typeid() function is not valid within a client LIBMI application.

Looking Up Cast Functions

A cast function is a user-defined function that converts one data type (the source data type) to a different data type (the target data type).

Tip: For more information on how to register a cast function, see "Extending Informix Dynamic Server 2000."

The way that a cast is called depends on the type of the cast, as the following table shows.

Type of Cast How It Is Called
Built-in cast Called by the database server automatically when built-in types need conversion in an SQL statement or a UDR call
Implicit cast Called by the server automatically when castable data types are part of an SQL statement
Explicit cast
  • Called explicitly within an SQL statement with the :: operator or CAST AS keywords
  • Called explicitly within a DataBlade API module with the Fastpath interface
  • To look up a cast function by its source and target data types, use one of the following Fastpath look-up functions.

    DataBlade API Function How It Looks Up a Cast Function
    mi_cast_get() Looks up a cast function for source and target data types specified as type identifiers
    mi_td_cast_get() Looks up a cast function for source and type data types specified as type descriptors

    The mi_cast_get() and mi_td_cast_get() functions perform the following steps:

    1. Ask the database server to look up the cast function in the syscasts system catalog.
    2. Once the function locates a syscasts entry for the cast function, it obtains routine information for the cast function from the sysprocedures system catalog table. These functions also determine the type of cast that the cast function performs: an explicit cast, an implicit cast, or a built-in cast.

    3. Allocate a function descriptor for the cast function and save the routine sequence in this descriptor.
    4. You can obtain information about the UDR from this function descriptor. For more information, see Obtaining Information from a Function Descriptor.

    5. Allocate an MI_FPARAM structure for the function descriptor.
    6. You can get a pointer to this structure with the mi_fparam_get() function. For more information, see Obtaining the MI_FPARAM Structure. You can also allocate your own MI_FPARAM structure to use instead of this automatically allocated one. For more information, see Using a User-Allocated MI_FPARAM Structure.

    7. Return a pointer to the function descriptor that was allocated for the cast function.
    8. Subsequent calls to mi_routine_exec() can use this function descriptor to identify the cast function to execute. For more information, see Executing the Routine.

      Tip: The mi_cast_get() and mi_td_cast_get() functions search for cast functions only in the syscasts system catalog table. Therefore, these functions can locate only cast functions that the CREATE CAST statement has registered.

    Suppose the following CREATE CAST statements register explicit casts between the DECIMAL and mytype data types in your database:

    Figure 9-12 uses the mi_cast_get() function to obtain the function descriptor for a cast function that casts from a DECIMAL data type to the mytype data type.

    Figure 9-12
    Obtaining a Cast Function for a
    DECIMAL-to-mytype
    Cast

    The mi_cast_get() function allocates and initializes a function descriptor, fdesc2, for the dec_to_mt() cast function. The src_type and trgt_type variables are pointers to the type identifiers for the DECIMAL(5,3) and mytype data types, respectively.

    The mi_cast_get() function returns a NULL-valued pointer to indicate several different conditions. In Figure 9-12, the cast_status variable identifies which of these conditions has occurred, as follows.

    cast_status Value Condition
    MI_ERROR_CAST The mi_cast_get() function has not executed successfully.
    MI_NO_CAST No cast function exists between the specified source and target types.
    MI_NOP_CAST No cast function is needed between the specified source and target types.

    The switch statement handles the possible status cast_status values from the mi_cast_get() call.

    If you have type descriptors instead of type identifiers for the source and target types, use the mi_td_cast_get() function instead of mi_cast_get(). For example, the casting process might need information about scale and precision for built-in data types that have this information. A type descriptor stores scale and precision; a type identifier does not.

    You could replace the call to mi_cast_get() in Figure 9-12 with the following call to the mi_td_cast_get() function:

    The src_tdesc and trgt_tdesc variables are pointers to type descriptors for the DECIMAL(5,3) and mytype data types, respectively. The mi_type_typedesc() function creates type descriptors from the type identifiers that src_type and trgt_type reference.

    When you call mi_cast_get() or mi_td_cast_get() from a client LIBMI application, the function allocates a local copy (on the client computer) of the function descriptor and MI_FPARAM structure. You can use the function-descriptor and MI_FPARAM accessor functions within a client LIBMI application to access these local copies.

    Obtaining Information from a Function Descriptor

    You can use the following DataBlade API functions to obtain additional information about the user-defined routine or cast function that is associated with a function descriptor.

    DataBlade API Function Description
    mi_fparam_get() Returns a pointer to the MI_FPARAM structure that is associated with the function descriptor
    mi_routine_id_get() Returns the routine identifier for the UDR or cast function
    mi_func_handlesnulls() Determines whether the UDR or cast function handles NULL arguments
    mi_func_isvariant() Determines if the UDR or cast function is a variant function
    mi_func_negator() Determines if the UDR has a negator function

    Obtaining the MI_FPARAM Structure

    By default, the Fastpath look-up functions allocate an MI_FPARAM structure and assign a pointer to this structure in the function descriptor. To obtain the MI_FPARAM structure that is associated with a function descriptor, use the mi_fparam_get() function. After the call to mi_fparam_get(), you can use the MI_FPARAM accessor functions to retrieve information from the MI_FPARAM structure, such as argument information (Figure 9-1 on page 9-5) and return-value information (Figure 9-4 on page 9-10). For information about these accessor functions and the information that they can retrieve from an MI_FPARAM structure, see Accessing the Routine State with MI_FPARAM.

    Figure 9-11 on page 9-29 shows the use of the mi_fparam_get() function to obtain the MI_FPARAM structure that is associated with the numeric_func() user-defined function. This code fragment uses the mi_fp_nrets() accessor function to obtain the number of return values for numeric_func() from the MI_FPARAM structure.

    Tip: You can allocate your own MI_FPARAM structure for a UDR that you execute with the Fastpath interface. For more information, see Using a User-Allocated MI_FPARAM Structure.

    Obtaining the Routine Identifier

    To obtain the routine identifier for the UDR or cast function that a function descriptor describes, use the mi_routine_id_get() function. The routine identifier is a unique integer that identifies a user-defined routine within the sysprocedures system catalog. This routine identifier is stored in the procid column of sysprocedures.

    The following code fragment obtains the routine identifier for the numeric_func() function that accepts INTEGER arguments:

    If your UDR is executing many other UDRs and it needs to keep several function descriptors for subsequent execution, it can use the routine identifier to distinguish the different function descriptors.

    Determining If UDR Handles NULL Arguments

    To determine whether the UDR or cast function that a function descriptor describes can handle SQL NULL values as arguments, use the mi_func_handlesnulls() function. This function determines whether the UDR was registered with the HANDLESNULLS routine modifier of the CREATE FUNCTION or CREATE PROCEDURE statement. This routine modifier is stored in the handlesnulls column of sysprocedures.

    The mi_func_handlesnulls() function can return the following values.

    mi_func_handlesnulls() Return Value Meaning
    1 The routine that the function descriptor describes has been registered with the HANDLESNULLS routine modifier.
    2 The routine that the function descriptor describes has not been registered with the HANDLESNULLS routine modifier.
    MI_ERROR The mi_func_handlesnulls() function was not successful.

    By default, a C UDR does not handle NULL values. When the routine manager receives NULL arguments for such a UDR, it does not even invoke the UDR. It just returns a NULL value. You can use the mi_func_handlesnulls() function to determine whether to call Fastpath to invoke a UDR that receives a NULL argument.

    The code fragment in Figure 9-13 determines whether to invoke the numeric_func() function based on whether it handles NULL arguments.

    Figure 9-13
    Handling Execution of a UDR with NULL Arguments

    If numeric_func() handles NULL arguments, the mi_func_handlesnulls() function returns 1 and the code fragment invokes numeric_func() with a NULL argument. Otherwise, the code fragment does not invoke numeric_func(); it returns a NULL value.

    Checking for a Variant Function

    By default, a user-defined function is a variant function. A variant function has one of the following characteristics:

    A nonvariant function always returns the same value when it receives the same arguments and it has none of the above variant side effects. Therefore, nonvariant functions cannot contain SQL statements or access external files.

    To determine whether the UDR or cast function is a variant function from its function descriptor, use the mi_func_isvariant() function. This function determines whether the user-defined function was registered with the VARIANT or NOT VARIAnt routine modifier of the CREATE FUNCTION or CREATE PROCEDURE statement. If you do not specify the VARIANT or NOT VARIANT modifier, the variant column of sysprocedures indicates that the user-defined function is variant.

    For more information about variant and nonvariant functions, see Extending Informix Dynamic Server 2000.

    Checking for a Negator Function

    A negator function evaluates the Boolean NOT condition for its associated Boolean user-defined function. To determine whether the UDR has a negator function from its function descriptor, use the mi_func_isvariant() function. This function determines whether the user-defined function was registered with the NEGATOR routine modifier of the CREATE FUNCTION statement. The negator column of sysprocedures stores the name of any negator function. For more information about negator functions, see Creating Negator Functions.

    Executing the Routine

    The mi_routine_exec() function can execute any user-defined routine that is registered in the open database. Any UDR that you can use in an SQL statement, you can directly execute with mi_routine_exec(). Once you obtain a function descriptor for a registered UDR or cast function, the mi_routine_exec() function sends it to the routine manager for execution. You can use the function descriptor in repeated calls to mi_routine_exec(). This executed routine runs in the virtual processor (VP) that was defined for it. This VP is not necessarily the VP in which the calling user-defined routine runs.

    Important: You cannot use the Fastpath interface to execute iterator functions or SPL functions with the WITH RESUME keywords in their RETURN statement. However, to simulate iterator functionality, you can call the same UDR repeatedly, passing it the same MI_FPARAM structure. Each invocation of the UDR can return one value. For more information on iterator functions, see Writing an Iterator Function.

    The mi_routine_exec() function takes the following steps:

    1. Passes the argument values in its argument list to the UDR.
    2. Returns any return value from the user-defined function to the calling module

    Passing in Argument Values

    When you call mi_routine_exec(), you provide argument values for the UDR that Fastpath is to execute. Keep the following points in mind when you create the argument list for mi_routine_exec():

    The mi_routine_exec() function dispatches the UDR through the routine manager. Therefore, each UDR gets a call to mi_call() because the routine manager checks for sufficient space before it executes the UDR.

    Receiving the Return Value

    When the mi_routine_exec() function executes a user-defined function, it returns as an MI_DATUM value the return value of the user-defined function that it has executed. This MI_DATUM value contains a value appropriate for the passing mechanism for the data type. Most data types are to be passed by reference from the UDR. For a list of data types that can be passed by value, see Figure 2-18 on page 2-48.

    You can then use C casting to convert this MI_DATUM value to the appropriate data type. You can obtain information about the return type (such as its data type) from the MI_FPARAM structure.

    If the user-defined function returned an SQL NULL value, mi_routine_exec() returns a NULL-valued pointer and sets the status argument to MI_OK.

    For examples of how to receive a UDR return value from mi_routine_exec(), see Sample mi_routine_exec() Calls. For more information on MI_DATUM, see MI_DATUM Data Type.

    Sample mi_routine_exec() Calls

    The code fragment in Figure 9-14 uses the mi_routine_exec() function to execute the numeric_func() routine that has INTEGER parameters.

    Figure 9-14
    Executing the
    numeric_func() Function with INTEGER Arguments

    In Figure 9-14, the mi_routine_exec() function uses the fdesc function descriptor that the mi_routine_get() function obtained for the numeric_func() function that accepts INTEGER arguments and returns an INTEGER value (Figure 9-11 on page 9-29). The last two arguments to mi_routine_exec() are the integer argument values for numeric_func(). The ret_val variable is an MI_DATUM value for the mi_integer data type that the numeric_func() function returns.

    Figure 9-14 also tests the return status of mi_routine_exec() to check for the return value from numeric_func(). If the return value (ret_val) is a NULL-valued pointer, the code then determines whether this NULL indicates:

    Finally, the code fragment in Figure 9-14 casts the MI_DATUM that mi_routine_exec() has returned to an mi_integer value. The MI_DATUM contains the actual return value because the routine manager can pass integer values by value (they can fit into an MI_DATUM).

    Suppose the call to mi_routine_get() had been calling the version of numeric_func() that accepted a FLOAT argument and returned a FLOAT value, as follows:

    The call to mi_routine_exec() to execute this version of numeric_func() would require that the argument and the return value be passed by reference, because the FLOAT data type cannot be stored directly in an MI_DATUM value.

    Figure 9-15 shows a sample call to mi_routine_exec() to execute the numeric_func(FLOAT) user-defined function. Notice that the argument list to mi_routine_exec() passes the FLOAT value by reference and the returned FLOAT value is returned by reference.

    Figure 9-15
    Executing the
    numeric_func() Function with INTEGER Arguments

    The execution of a cast function is the same as that of a user-defined routine. The following call to mi_routine_exec() executes the DECIMAL-to-mytype cast function for which Figure 9-12 on page 9-33 obtained the function descriptor, fdesc2:

    The dec_val argument is an mi_decimal variable that contains the DECIMAL source data type to cast to the mytype target data type with the dec_to_mt() cast function. The ret_val variable is a MI_DATUM value of the mytype data type that contains the casted DECIMAL value.

    Reusing a Function Descriptor

    By default, when the Fastpath look-up functions (mi_routine_get(), mi_routine_get_by_typeid(), mi_func_desc_by_typeid(), mi_cast_get(), or mi_td_cast_get()) obtain a function descriptor, they allocate it with a PER_COMMAND memory duration. Therefore, the function descriptor remains allocated for the duration of the SQL command that invokes a UDR. If the same UDR executes many times within a single command, you can reuse this function descriptor for each invocation of the UDR. When you reuse the function descriptor, you save the overhead of looking up the UDR and allocating a function descriptor each time you reexecute the user-defined routine.

    The following code fragment opens a connection and obtains the function descriptor for the user-defined function equal() each time that the non_optimal() UDR is called:

    To optimize this code, you can cache the function descriptor in the MI_FPARAM structure. If you cache the function descriptor in the user state of the MI_FPARAM structure, you do not have to repeatedly call mi_routine_get() for each invocation of the equal() function. Instead, you can call mi_routine_get() only in the first invocation of equal(). You can also cache the connection description in MI_FPARAM.

    The following code fragment opens a connection and gets the function descriptor for the first invocation of the user-defined function equal() only. It caches these descriptors into the user_state structure, which it stores in the user-state pointer of MI_FPARAM, for subsequent invocations of equal():

    Using a User-Allocated MI_FPARAM Structure

    The Fastpath look-up functions (mi_cast_get(), mi_func_desc_by_typeid(), mi_routine_get(), mi_routine_get_by_typeid(), and mi_td_cast_get()) automatically allocate an MI_FPARAM structure and save a pointer to this structure in the function descriptor that they allocate. However, there are some cases in which you might want to allocate your own MI_FPARAM structure for the UDR that Fastpath executes.

    The following DataBlade API functions support use of a user-allocated MI_FPARAM structure.

    DataBlade API Function Description
    mi_fparam_allocate() Allocates a new MI_FPARAM structure
    mi_fparam_copy() Copies an existing MI_FPARAM structure into a new MI_FPARAM structure
    mi_fparam_free() Frees a user-allocated MI_FPARAM structure
    mi_fp_usr_fparam() Determines whether a specified MI_FPARAM structure was allocated by the database server or by a user-defined routine

    Creating a User-Allocated MI_FPARAM Structure

    The following DataBlade API function creates a user-allocated MI_FPARAM structure and returns a pointer to this newly allocated structure

    Both these functions are constructor functions for an MI_FPARAM structure. They allocate the user-allocated MI_FPARAM in the current memory duration. By default, the current memory duration is PER_ROUTINE. For calling a UDR with Fastpath, the PER_ROUTINE memory duration refers to the duration of the calling UDR, not the UDR that you call with Fastpath.

    If you have changed the current memory duration with the mi_switch_mem_duration() function, mi_fparam_allocate() or mi_fparam_copy() uses the current memory duration that mi_switch_mem_duration() has specified for the MI_FPARAM structure that it allocates.

    If the current memory duration is not acceptable for your use of the MI_FPARAM structure, call mi_switch_mem_duration() with the desired memory duration before the call to mi_fparam_allocate() or mi_fparam_copy(). Keep in mind that when you call mi_switch_mem_duration(), you change the current memory duration for all subsequent memory allocations, including those made by mi_alloc().

    Using the User-Allocated MI_FPARAM

    For C UDRs, one of the primary uses of a user-allocated MI_FPARAM structure is for data-type control for generic routines. If you are calling a generic UDR, one that handles many possible data types, you can set the arguments in the MI_FPARAM to the specific data type. Possible uses for generic UDRs include over collection types or over type hierarchies. You can set the MI_FPARAM to accept the correct parameter data types for a particular invocation of the routine. For example, you could pass an employee_t data type into a UDR that was defined with the supertype person_t.

    Suppose you have a type hierarchy with person_t as the supertype and employee_t as a subtype of person. The person_udr() UDR might be called with either the person_t or employee_t data type in the first two arguments. Suppose person_udr() needs to use Fastpath to execute another UDR, called person_udr2(), to handle some additional task. The following code fragment shows how the second and third arguments from person_udr() are passed to person_udr2().

    In the preceding code fragment, the first argument of person_udr2() is set to have the same type as the second argument of person_udr(), based on its MI_FPARAM structure. This implementation assumes that person_udr2() needs to know the actual data type of the argument, not the supertype.

    Tip: Another possible use of a user-allocated MI_FPARAM is in conjunction with per-session function descriptors. Per-session function descriptors are a controlled feature of the DataBlade API and intended for use only by DataBlade partners. Contact your Informix sales representative for more information.

    Passing the User-Allocated MI_FPARAM

    To pass the user-allocated MI_FPARAM structure to the Fastpath interface, specify it as the last argument of the argument list that you provide to mi_routine_exec(). The following call to mi_routine_exec() executes the numeric_func() UDR (see Figure 9-11 on page 9-29) and specifies a user-allocated MI_FPARAM structure:

    Freeing a User-Allocated MI_FPARAM

    The database server automatically deallocates memory for the MI_FPARAM structures that it allocates for the function descriptor of a UDR. However, the database server does not deallocate any MI_FPARAM structure that you allocate. A user-defined MI_FPARAM structure has a default memory duration of the current memory duration. To conserve resources, use the mi_fparam_free() function to explicitly deallocate the user-defined MI_FPARAM structure once your DataBlade API module no longer needs it. The mi_fparam_free() function is the destructor function for a user-defined MI_FPARAM structure. It frees the MI_FPARAM structure and any resources that are associated with it.

    Releasing Routine Resources

    A function descriptor for a user-defined routine has a default memory duration of PER_COMMAND. Therefore, a function descriptor remains active until whichever of the following events occurs first:

    To conserve resources, use the mi_routine_end() function to explicitly deallocate the function descriptor once your DataBlade API module no longer needs it. The mi_routine_end() function is the destructor function for a function descriptor. It frees the function descriptor and any resources that are associated with it.

    The following call to mi_routine_end() explicitly releases the resources for the fdesc function descriptor that the code in Figure 9-11 on page 9-29 and Figure 9-14 on page 9-41 uses:

    Important: Informix recommends that you explicitly deallocate function descriptors with mi_routine_end() once you no longer need them. Otherwise, these function descriptors remain until the end of the associated SQL command.


    Informix DataBlade API Programmer's Manual, Version 9.2
    Copyright © 1999, Informix Software, Inc. All rights reserved