informix
Informix DataBlade API Programmer's Manual
Creating Special-Purpose UDRs

Writing an Iterator Function

An iterator function is a user-defined function that returns to its calling SQL statement several times, each time returning a value. The database server gathers these returned values together in an active set. To access a value in the active set, you must obtain it from a database cursor. Therefore, an iterator function is a cursor function because it must be associated with a cursor when it is executed.

Tip: This section describes how to create an iterator function that is written in C. For general information on how to create functions, see "Extending Informix Dynamic Server 2000."

The database server might execute an iterator function many times. It groups these iterations into the iterator-status values and puts the iterator status for a given iteration in the MI_FPARAM structure. Within an iterator function, you examine the MI_FPARAM structure for an iterator status to determine which actions the iterator function must take.

Tip: The Informix BladeSmith development tool, which is part of the DataBlade Developers Kit, automatically generates C source code for an iterator function as well as the SQL statements to register the iterator function. For more information, see the "DataBlade Developers Kit User's Guide."

The following table lists the different points at which the database server calls an iterator function and the associated iterator-status values.

When Is the Iterator Function Called? What Does the Iterator Function Do? Iterator-Status Constant in MI_FPARAM
The first time that the iterator function is called Initializes the iterations SET_INIT
Once for each item in the active set Returns one item of the active set SET_RETONE
After the last item of the active set is returned Releases iteration resources SET_END

To implement an iterator function with a C user-defined function, follow these steps:

  1. Declare the iterator function so that its return value has a data type that is compatible with one of the items in the active set.
  2. For example, to return an active set of integer values, declare the iterator function to return the mi_integer data type.

  3. Include an MI_FPARAM structure as the last parameter of the C declaration of the iterator function.
  4. The MI_FPARAM structure holds the iterator status, the iterator-completion flag, and the user-state pointer.

  5. Within the iterator function, obtain the iterator status from the MI_FPARAM structure with the mi_fp_request() function.
  6. This function returns the iterator-status constant (SET_INIT, SET_RETONE, or SET_END) that the database server has set for the distinct groups of iterations of the iterator function.

  7. For each of the iterator-status values, take the appropriate actions within the iterator function.

    Iterator-Status Value For More Information
    SET_INIT Initializing the Iterations
    SET_RETONE Returning One Active-Set Item
    SET_END Releasing Iteration Resources
  8. Register the iterator function as a user-defined function with the ITERATOR routine modifier in the CREATE FUNCTION statement.
  9. Omit the MI_FPARAM parameter from the parameter list when you register the iterator function. For more information on how to register a user-defined routine, see Registering a C UDR.

The Fibonacci series is a list of numbers for which each value is the sum of the previous two. For example, the Fibonacci series up to a stop value of 20 is as follows:

Figure 13-1 is an implementation of an iterator function called fibGen(). This function builds an active set that contains a Fibonacci series of numbers up to a specified stop value.

Figure 13-1
The fibGen() Iterator Function

The database server calls this fibGen() iterator function at the following execution points:

When the iterator function reaches the last item, call the mi_fp_setisdone() function to set the iterator-completion flag of the MI_FPARAM structure to one (1). This flag indicates to the database server that it has reached the end condition for the iterator function. The database server no longer needs to continue calling the iterator function with the SET_RETONE iterator-status value. Instead, it calls the iterator function one more time, with the SET_END status value.

Important: Make sure that you include a call to the mi_fp_setisdone() function within your iterator function that sets the iterator-completion flag to one (1). Without this call, the database server never reaches an end condition for the iteration, which causes it to iterate the function in an infinite loop.

In Figure 13-1 on page 13-6, the fibGen() iterator function determines if it has reached an end condition after it calls fibGen_retone(). It makes this determination as follows:

Initializing the Iterations

The first time that the database server calls the iterator function, the database server passes it an MI_FPARAM structure with the iterator status set to SET_INIT and the user-state pointer set to NULL. When the iterator function obtains this iterator-status value, it can perform the following initialization tasks for the iterator function:

You can perform these initialization tasks directly in the iterator function or you can declare a separate iterator-initialization function, which the iterator function calls when it receives the SET_INIT iterator-status value. Declare the iterator-initialization function to return the same data type as the main iterator function. However, the database server ignores the return value of this function; it does not put this return value in the active set.

Figure 13-2 implements an iterator-initialization function, call fibGen_init(), which the fibGen() iterator function (Figure 13-1 on page 13-6) calls when it obtains the SET_INIT iterator-status value.

Figure 13-2
The fibGen_init() Initialization Function

The fibGen_init() function returns an mi_integer value (0) because the main iterator function, fibGen(), returns an active set of mi_integer values. However, the database server does not return this value as part of the active set. Once fibGen_init() completes, the database server calls the next iteration of fibGen() with an iterator-status value of SET_RETONE, to return the first item of the active set.

Returning One Active-Set Item

When the iterator status is SET_RETONE, the iterator function can return one item of the active set. When the iterator function obtains this iterator-status value, it can perform the iteration tasks needed to generate one item of the active set.

You can perform these iterator tasks directly in the iterator function or you can declare a separate iterator-value-return function, which the iterator function calls when it receives the SET_RETONE iterator-status value. Declare the iterator-value-return function to return the same data type as the main iterator function. The database server puts the return value of this function in the active set.

Figure 13-3 implements an iterator-value-return function, called fibGen_retone(), which the fibGen() iterator function (Figure 13-1 on page 13-6) calls each time it obtains the SET_RETONE iterator status.

Figure 13-3
The fibGen_retone() Value-Return Function

Each item in the active set that the fibGen() function generates is one call to the fibGen_retone() function. The fibGen_retone() function returns one number of the Fibonacci series. It uses the mi_fp_funcstate() function to obtain the user-state pointer from the MI_FPARAM structure. This user-state pointer points to a fibstate structure (which the fibGen_init() function in Figure 13-2 on page 13-10 allocated).

From the information in the fibstate structure, the fibGen_retone() function determines the next Fibonacci number and stores it in the next variable. The function then updates the fibstate structure for the next iteration of fibGen(). Finally, the function returns one item of the active set: the value of next.

Releasing Iteration Resources

Once the mi_fp_setisdone() function sets the iterator-completion flag to 1, the database server calls the iterator function one last time with the iterator-status value in the MI_FPARAM structure set to SET_END. When the iterator function obtains this iterator-status value, it can perform any tasks needed to deallocate resources that the iterator function has allocated.

Important: Only free resources that you have allocated. Do not attempt to free resources that the database server has allocated (such as MI_FPARAM).

You can perform these deallocation tasks directly in the iterator function or you can declare a separate iterator-end function, which the iterator function calls when it receives the SET_END iterator-status value. Declare the iterator-end function to return the same data type as the main iterator function. However, the database server ignores the return value of this function; it does not put this return value in the active set.

Figure 13-4 implements an iterator-end function, called fibGen_end(), which the fibGen() iterator function (see Figure 13-1 on page 13-6) calls when it obtains the SET_END iterator-status value.

Figure 13-4
The fibGen_end() Iterator-End Function

The fibGen_end() function uses the mi_fp_funcstate() function to obtain the user-state pointer from the MI_FPARAM structure. It then calls the mi_free() function to free the resources in the fibstate state structure, which the fibGen_init() function (see Figure 13-2 on page 13-10) has allocated. The fibGen_end() function returns an mi_integer value (0) because the main iterator function, fibGen(), returns an active set of mi_integer values.

Calling an Iterator Function from an SQL Statement

For end users to be able to use an iterator function within an SQL statement, take the following steps:

Registering the Iterator Function

Register the iterator function with the CREATE FUNCTION statement. The CREATE FUNCTION must include the ITERATOR routine modifier to tell the database server that it must call the function until the iterator-completion flag is set to 1.

Tip: If your iterator function calls other functions (such as an iteration-initialization function, iterator-value-return function, or iterator-end function) to implement its iterations, you do not have to register these other functions with the CREATE FUNCTION statement.

The following CREATE FUNCTION statement registers the fibGen() iterator function, which Figure 13-1 on page 13-6 defines, in the database:

This statement assumes that the object code for the fibGen() function resides in the UNIX fib.so shared-object file in the directory that the USERFUNCDIR environment variable specifies. It also assumes that USERFUNCDIR was set in the server environment.

For more information on how to register a user-defined function, see Registering a C UDR.

Executing the Iterator Function

Once you register an iterator function (and assign it the appropriate privileges), users who have Execute privilege can execute it. However, because an iterator function returns an active set of items, you must associate the function with a cursor. The cursor holds the active set, which the application can then access one at a time.

Each iteration of the iterator function returns one item of the active set. To execute an iterator function, you must associate it with a cursor. This EXECUTE FUNCTION statement generates an active set that contains the following Fibonacci values:

To obtain these values from within an application, you must associate the EXECUTE FUNCTION statement with a cursor to execute the function.

Once you register the fibGen() function, you can execute the following SQL statement from DB-Access:

From within a DataBlade API module, execute fibGen() with the mi_exec_prepared_statement() function, as follows:

For more information on how to use mi_exec_prepared_statement(), see Executing Prepared SQL Statements.


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