When the routine manager invokes a C UDR, the routine manager passes to the UDR any argument values that the calling SQL statement provided. When you write a C UDR, you can define routine parameters that indicate the data types of the arguments that you expect the UDR to handle.
This section provides information about how to define routine parameters for the following UDR arguments:
The routine manager uses the parameter data types in routine resolution. Therefore, you can have multiple UDRs with the same name, provided that their parameter lists uniquely identify the UDRs. For more information, see Routine Resolution.
Routine parameters are optional. If your UDR does not need parameters, follow your C-compiler conventions for the syntax to use when declaring the C function.
When an SQL statement invokes a UDR, the statement can specify column values or expressions to pass to the UDR. The routine manager passes these argument values to a UDR as MI_DATUM values. The data type of each argument determines the passing mechanism that the routine manager uses for the argument value, as follows:
The passing mechanism that the routine manager uses for a particular argument determines how you must declare the corresponding parameter of the UDR. For more information about how the routine manager passes argument values to a C UDR, see The MI_DATUM Data Type and Pushing Arguments Onto the Stack.
When an argument has a value that cannot fit into an MI_DATUM structure, the routine manager passes the argument by reference. For each of these pass-by-reference arguments, you declare a parameter that is a pointer to a value of the parameter data type, in the C-function declaration.
Figure 67 shows the bigger_double( ) user-defined function, which compares two mi_double_precision values. Because the routine manager passes mi_double_precision values by reference, bigger_double( ) declares the two parameters as pointers to values of the mi_double_precision data type.
mi_double_precision *bigger_double(left, right) mi_double_precision *left, *right; { mi_double_precision *dpp; dpp = mi_alloc(sizeof(mi_double_precision)); if ( *left > *right ) { *dpp = *left; return(dpp); } else { *dpp = *right; return(dpp); } }
Any C-language code that calls bigger_double( ) must pass the mi_double_precision values by reference, as in the following sample call:
mi_double_precision double1, double2, *result; double1 = 13497.931669; double2 = 235521832.00484; result = bigger_double(&double1, &double2);
Values passed into a UDR are often also used in other places in the SQL statement. If your UDR modifies a pass-by-reference value, successive routines in the SQL statement might use the modified value. When your UDR is run within the context of an SQL statement, a routine that runs before it can see (and possibly modify) any pass-by-reference values.
When an argument has a data type that can fit into an MI_DATUM structure, the routine manager passes the argument by value. Table 13 lists data types for arguments that you can pass by value. For these pass-by-value arguments, you declare a parameter as the actual parameter data type in the C-function declaration.
Figure 68 shows the bigger_int( ) UDR, which compares two mi_integer values. Because the routine manager passes mi_integer values by value, the UDR declares the two parameters with the mi_integer data type, not as pointers to mi_integer.
mi_integer bigger_int(left, right) mi_integer left, right; { if ( left > right ) return(left); else return(right); }
Any C-language code that calls bigger_int( ) must also pass the mi_integer values by value, as in the following sample call:
mi_integer int1, int2, result; ... int1 = 6; in2 = 8; result = bigger_int(int1, int2);
The routine manager passes an MI_FPARAM structure into every UDR that it executes. This structure contains routine-state information about the UDR, such as information about arguments and return values. Because the routine manager automatically passes an MI_FPARAM structure to a UDR, you do not need to explicitly declare this structure in most C-function declarations.
You should include an MI_FPARAM declaration in the C-function declaration in the following cases:
When you declare an MI_FPARAM parameter, this declaration must be the last parameter in the C declaration of your UDR. For more information about the DataBlade API functions that access the routine-state information from MI_FPARAM, see Accessing MI_FPARAM Routine-State Information.
A C UDR always gets at least one argument: a pointer to the MI_FPARAM structure. When the parameter list of your SQL UDR is empty, you must still include a declaration for the MI_FPARAM structure, even if the UDR does not access routine-state information.
For example, the bigger_double( ) user-defined function in Figure 67 does not include a declaration for the MI_FPARAM structure because it does not need to access routine-state information and it has other parameters. However, suppose you register a user-defined function named func_noargs( ) that does not require any arguments:
CREATE FUNCTION func_noargs( ) RETURNS INTEGER EXTERNAL NAME '/usr/lib/udrs/udrs.so' LANGUAGE C;
In the C UDR, you can declare the func_noargs( ) function with a single parameter, a pointer to the MI_FPARAM structure:
mi_integer func_noargs(MI_FPARAM *fparam) { ... }
The declaration of the MI_FPARAM structure allows the routine manager to pass this structure into the UDR.