Example C iterator function

To write an iterator C function, you use DataBlade® API functions, such as mi_fp_request(), mi_fp_setfuncstate(), mi_fp_setisdone(), and so on, with the MI_FPARAM data structure.

A C UDR can return only one value; therefore, there can be only one column in the virtual column list in the FROM clause. However, a C UDR can return a row type, which can capture multiple return values as a unit.

The following example demonstrates how to write a C iterator function and use it in the FROM clause; relevant DataBlade API and iterator states are highlighted.

The function fibseries() is an iterator function that returns the Fibonacci series up to the value passed to it as an argument.
create function fibseries(int x)
returns int with (handlesnulls,iterator, parallelizable)
external name "$USERFUNCDIR/fib.so"
language c;

/* A Function to return a set of integer. This function takes 
stop val as a parameter and returns a fibonaucci series up to 
stop val. 

* Three states of fparam :
*
* SET_INIT: Allocate the function state structure defined. 
This State Structure is allocated in PER_COMMAND duration to
hold the memory till the end of the command.
Make the fparam structure point to the State Structure.
Set the first two numbers of the series i.e 0 and 1; And 
set the stop val field of State Structure to the stop val passed 
to the function. 

* SET_RETONE: Computes the next number in the series. Compares 
it with the stop val to check if the exit criteria is met.  
num1 = num2;num2 = next number in the series.

* SET_END: Frees the user Allocated Func State structure.
*/

#include <milib.h>
typedef struct fibState1 {
   mi_integer fib_prec1;
   mi_integer fib_prec2;
   mi_integer fib_ncomputed;
   mi_integer fib_endval;
}fibState;
mi_integer
fibseries(endval,fparam)
mi_integer endval;
MI_FPARAM  *fparam;
{
     fibState   *fibstate;
     mi_integer next;
     switch(mi_fp_request(fparam)) {
        case SET_INIT :
             fibstate = (fibState *) mi_dalloc 
(sizeof(fibState),PER_COMMAND);

             mi_fp_setfuncstate(fparam,(void *)fibstate);
             if (mi_fp_argisnull(fparam,0) || endval < 0) {
                mi_fp_setreturnisnull(fparam,0,1);
                break;
             }
             if (endval < 1) {
                fibstate->fib_prec1 = 0;
                fibstate->fib_prec2 = 1;
                fibstate->fib_ncomputed = 1;
                fibstate->fib_endval = endval; 
             }
             else {
                fibstate->fib_prec1 = 0;
                fibstate->fib_prec2 = 1;
                fibstate->fib_ncomputed = 0;
                fibstate->fib_endval = endval;                 
             }
             break;
        case SET_RETONE :
             fibstate = mi_fp_funcstate(fparam);
             if (fibstate->fib_ncomputed < 2) {
                return((fibstate->fib_ncomputed++ == 0) ? 0 : 1);
             }
             next = fibstate->fib_prec1 + fibstate->fib_prec2;
             if (next > fibstate->fib_endval) {
                mi_fp_setisdone(fparam,1);
                return 0;
             }
             if (next == 0) {
                fibstate->fib_prec1 = 0;
                fibstate->fib_prec1 = 1;
             }
             else {
                fibstate->fib_prec1 = fibstate->fib_prec2;
                fibstate->fib_prec2 = next;
                
             }
             return (next);
        case SET_END :
             fibstate = mi_fp_funcstate(fparam); 
             mi_free(fibstate);
             break;
     }
}
This function can be used in the FROM clause of a SELECT query:
select vcol1 from table (function fibseries(100)) vtab1(vcol1);