![]() |
|
When you write a user-defined routine, consider the following:
The routine name and routine parameters make up the routine signature for the routine. The routine signature uniquely identifies the user-defined routine in the database. For more information, see The Routine Signature.
Consider the following questions about routine naming and design:
Choose sensible names for your routines. Make the routine name easy to remember and have it succinctly describe what the routine does. The database server supports polymorphism, which allows multiple routines to have the same name. This ability to assign one name to multiple routines is called routine overloading. For more information on routine overloading, refer to Overloading Routines.
Routine overloading is contrary to programming practice in some high-level languages. For example, a C programmer might be tempted to create functions with the following names that return the larger of their arguments:
In SQL, these routines are better defined in the following way:
The naming scheme in the second example allows users to ignore the types of the arguments when they call the routine. They simply remember what the routine does and let the database server choose which routine to call based on the argument types. This feature makes the user-defined routine simpler to use.
When you invoke a user-defined routine, you can pass it optional argument values. Each argument value corresponds to a parameter of the routine.
Limit the number of arguments in your user-defined routines and make sure that these arguments do not make the routine modal. A modal routine uses a special argument as a sort of flag to determine which of several behaviors it should take. For example, the following statement shows a routine call to compute containment of spatial values:
This routine determines whether the first polygon contains the second polygon or whether the second contains the first. The caller supplies an integer argument (for example, 1 or 0) to identify which value to compute. This is modal behavior; the mode of the routine changes depending on the value of the third argument.
In the following example, the routine names clearly explain what computation is performed:
Always construct your routines to be nonmodal, as in the second example.
You define routine parameters in a parameter list when you declare the routine. In the parameter list, each parameter provides the name and data type of a value that the routine expects to handle. Routine parameters are optional; you can write a UDR that has no input parameters.
When you invoke the routine, the argument value must have a data type that is compatible with the parameter data type. If the data types are not the same, the database server tries to resolve the differences. For more information, see The Routine-Resolution Process.
The way that you declare a user-defined routine depends on the language in which you write that routine.
The parameters in an SPL routine must be declared with SQL data types. For more information, see Executing an SPL Routine.
For routines written in an external language (C or Java), you use the syntax of the external language to declare the routine. The routine parameters indicate the argument data types that the routine expects to handle.
You declare the routine parameters with data types that the external language supports. However, when you register the routine with CREATE FUNCTION or CREATE PROCEDURE, you use SQL data types for the parameters. (For more information, see Registering Parameters and a Return Value.) Therefore, you must ensure that these external data types are compatible with the SQL data types that the routine registration specifies.
For UDRs written in C, the DataBlade API provides special data types for use with SQL data types. For most of these special data types, you must use the pass-by-reference mechanism. However, for a few data types, you can use the pass-by-value mechanism. For more information, see the chapter in DataBlade API data types in the DataBlade API Programmer's Manual.
Every UDR written in Java maps to an external Java static method whose class resides in a JAR file that has been installed in a database. The SQL-to-Java data type mapping is done according to the JDBC specification. For more information, refer to Creating UDRs in Java.
A common use of a user-defined routine is to return a value to the calling SQL statement. A user-defined routine that returns a value is called a user-defined function.
For information on how to specify the data type of the return value of a user-defined function, see Registering a User-Defined Routine.
By default, a user-defined function is a variant function. A variant function has any of the following characteristics:
You can explicitly specify a variant function with the VARIANT keyword. However, because a function is variant by default, this keyword is not required.
A nonvariant function always returns the same value when it receives the same argument, and it has none of the preceding variant side effects. Therefore, nonvariant functions cannot contain SQL statements or access external files. For nonvariant functions, the database server might decide at execution time to cache the return values for expensive functions or to parallelize the query. You can create a functional index only on a nonvariant function. You specify a nonvariant function with the NOT VARIANT keywords.
Within the CREATE FUNCTION statement, you can specify VARIANT or NOT VARIANT in either of these places:
If you specify these keywords in both of these locations, the two specifications must be the same.
By definition, an external function returns only one value. However, the database server provides the following methods for external routines to return multiple values:
To create an external function that returns more than one value, perform the following actions:
Tip: Although this section discusses the use of SLVs in the context of an OUT parameter in an external function, you can use SLVs and OUT parameters in SPL functions.
An OUT parameter is a function parameter whose argument value the database server passes by reference to the routine. The external function can change the value of this parameter and return a new value through the parameter. Each external function can have at most one OUT parameter.
You can define OUT parameters for the following external routines:
To be called in a WHERE clause, a routine must return a BOOLEAN value. Therefore, only user-defined functions can be called in a WHERE clause.
The OUT parameter does not pass any data into the user-defined routine. At the time the function is called, the SLV does not reference any actual value. The database server passes only a pointer to some space where the function can store a value. The external function cannot retrieve values from this reserved space. By contrast, when a pure C-language program passes a pointer to a function, this pointer can point to a valid value, and the function can examine the current value before it modifies and returns the pointer.
Important: In the user-defined function, do not try to read from the address of the OUT parameter pointer because the value is meaningless.
To return a value from an external routine with an OUT parameter
A statement-local variable (SLV) transmits an OUT parameter from a user-defined function to other parts of an SQL statement. An SLV is local to the SQL statement; that is, it is only valid for the life of the SQL statement. It provides a temporary name by which to access the OUT parameter value.
In the SQL statement that calls the user-defined function, declare the SLV with the following syntax:
For example, the following SELECT statement declares an SLV y that is typed as an INTEGER in its WHERE clause and then accesses the y SLV in the WHERE clause:
For more information on the syntax and use of an SLV, see the description of function expressions within the Expression segment in the Informix Guide to SQL: Syntax.
By default, a user-defined function returns only one value; that is, it calculates its return value and returns only once to its calling SQL statement. Although the section OUT Parameters and Statement-Local Variables describes how to return more than one value from a user-defined function, the function still returns all these values at the same time to the calling SQL statement. User-defined functions that return their result in a single return to the calling SQL statement are called noncursor functions because they do not require a database cursor to be executed. For information on how to invoke noncursor functions, see Invoking a User-Defined Routine.
However, you can write a user-defined function that returns to its calling SQL statement several times, each time returning a value. Such a user-defined function is called an iterator function. An iterator function is a cursor function because it must be associated with a cursor when it is executed. The cursor holds the values that the cursor function repeatedly returns to the SQL statement. The calling program can then access the cursor to obtain each returned value, one at a time. The contents of the cursor are called an active set. Each time the iterator function returns a value to the calling SQL statement, it adds one item to the active set.
Tip: An iterator function is similar to an SPL function that contains the RETURN WITH RESUME statement.
Creating an Iterator Function
You can write iterator functions in C or in Java:
By default, an external function is not an iterator. To define an iterator function, you must register the function with the ITERATOR routine modifier. The following sample CREATE FUNCTION statement shows how to register the function TopK() as an iterator function in C:
You can invoke an iterator function with the EXECUTE FUNCTION statement in one of the following methods:
The SQL/PSM standard is available for UDR development. In addition, Informix publishes a collection of standards for DataBlade module development. These standards are available from the DataBlade Developers Program. The most important rules govern the naming of data types and routines. DataBlade modules share these name spaces, so you must follow the naming guidelines to guarantee that no problems occur when you register multiple DataBlade modules in a single database.
Tip: Informix recommends that you use the DataBlade Developers Kit (DBDK), Version 4.0 or later, to help write UDRs. Although it is possible to create a DataBlade without DBDK, it is not desirable. DBDK enforces standards on DataBlade modules that facilitate migration between different versions of the database server.
In addition, the standards for 64-bit clean implementation, safe function-calling practices, thread-safe development, and platform portability are important. Adherence to these standards ensures that UDR modules are portable across platforms.
Ask yourself the following questions when coding your user-defined routine: