INFORMIX
Extending INFORMIX-Universal Server: User-Defined Routines
Chapter 2: Routine Overloading and Routine Resolution
Home Contents Index Master Index New Book

The Routine-Resolution Process

Routine resolution refers to the process in which the database server determines which routine to execute when you overload a routine. The database server invokes routine resolution implicitly when a routine is invoked by a user or another routine. You need to understand the routine-resolution process to:

When a user or another routine invokes a routine, the database server searches for a signature that matches the routine name and arguments. If the database contains a routine with a matching signature, the database server executes this routine. If no exact match exists, the database server searches for a routine to substitute.

When several arguments are passed to a routine, the database server first tries to match the leftmost argument. The database server checks for a candidate routine that has the same data type as the leftmost argument. If no exact match exists for the first argument, the database server searches the candidate list of routines using a precedence order of data types.

The database server continues matching the arguments from left to right.

Candidate List of Routines

The database server finds a list of candidate routines from the sysprocedures system catalog that match the following:

Important: The candidate list contains only routines for which the current session has EXECUTE permission.
ANSI
In an ANSI-compliant database, the candidate list contains only routines that belong to the current user and the user informix.

Precedence List of Data Types

To determine which routine in the candidate list might be appropriate to an argument type, the database server builds a precedence list of data types for the argument.The routine-resolution process uses the following precedence order to match the data types of arguments in the list of candidate routines:

    1. Data type of the argument passed to a routine

    2. If an argument passed to a routine is a subtype in a type hierarchy, Universal Server checks up the type hierarchy tree for a routine to execute. For more information, refer to "Routine Resolution Within a Type Hierarchy".

    3. If an argument passed to a routine is a distinct type, Universal Server checks the source type for a routine to execute. If the source type is itself a distinct type, Universal Server checks the source type of that distinct type. For more information, refer to "Routine Resolution with Distinct Data Types".

    4. If an argument passed to a routine is a built-in type, Universal Server checks the candidate list for a data type in the built-in data type precedence list for the passed argument. For more information on the precedence of each built-in data type, refer to "Precedence List for Built-In Data Types".

    If a match exists in this built-in data type precedence list, the database server searches for an implicit cast function.

    5. The database server adds implicit casts of the data types in steps 1 through 4 to the precedence list, in the order that the data types were added.

    6. If an argument passed to a routine is a collection type, Universal Server adds the generic type of the collection to the precedence list for the passed argument.

If no qualifying routine exists, the database server returns an error message.

If the routine-resolution process locates more than one qualifying routine, the database server returns an error message.

Routine Resolution Within a Type Hierarchy

A type hierarchy is a relationship that you define among named row types in which subtypes inherit representation (data fields) and behavior (routines, operators, rules) from a named row above it (supertype) and can add additional fields and routines. The subtype can add additional data attributes and behavior to those inherited from the supertype.

Figure 2-3 shows the CREATE statements to define a sample hierarchy.

Figure 2-3
Sample Data Type Hierarchy

When a data type in the argument list does not match the data type of the parameter in the same position of the routine signature, the database server searches for a routine with a parameter in the same position that is the closest supertype of that argument.

For example, suppose you create an overload function, bonus(), for the sample type hierarchy in Figure 2-3. You create the bonus() function on the root supertype and a subtype and invoke the bonus() function with the following statements:

The routine-resolution process goes through the following steps:

    1. Processes the leftmost argument first. a. Looks for a candidate routine named bonus with a row type parameter of student_emp.

b. Because student_emp is a subtype of trainee, the database server looks for a candidate routine with a parameter of type trainee in the first position.

    2. The database server processes the second argument next. a. Looks for a candidate routine with a second parameter of data type integer.

b. Because the second parameter is a built-in data type, the database server goes to the precedence list in Figure 2-5.

c. Because a built-in cast exists from the integer to float data types, the database server casts the integer argument to float before the execution of the bonus function.

    3. Because of the left-to-right rule for processing the arguments, the database server executes the second function, bonus(trainee,float).

Routine Resolution with Distinct Data Types

A distinct data type has the same internal storage representation as an existing data type, but it has a different name and cannot be compared to the source type without casting. Distinct types inherit functions from their source types.

When a distinct data type in the argument list does not match the data type of the parameter in the same position of the routine signature, the database server searches for a routine that accepts the source type in the position of that argument. If the source type is itself a distinct type, the database server checks the source type of that distinct type.

The candidate list can contain a routine with an argument that is the source type of the invoked routine argument. However, if the source type is not in the precedence list for that data type, then the routine-resolution process eliminates that candidate.

For example, suppose you create the following distinct data types and table:

Figure 2-4 shows a sample query that an SQL user might execute.

Figure 2-4
Sample Distinct Type Invocation

Although the source data types of the two arguments are the same, this query fails because p and s are different distinct data types.

Important: The routine-resolution process cannot match two different distinct types.
The database server chooses the built-in equals function when you explicitly cast the arguments, as the following query shows:

You can also write and register the following additional functions to allow the SQL user to use the SELECT statement in Figure 2-4:

Precedence List for Built-In Data Types

that has a parameter contained in the precedence list for the data type. Figure 2-5 lists the precedence for the built-in data types when an argument in the routine invocation does not match the parameter in the candidate list.

Figure 2-5
Precedence of Built-In Data Types

Data Type Precedence List

CHAR

VARCHAR, LVARCHAR

VARCHAR

LVARCHAR

NCHAR

NVARCHAR

NVARCHAR

None

SMALLINT

INT, INT8, DECIMAL, SMALLFLOAT, FLOAT

INT

INT8, DECIMAL, SMALLFLOAT, FLOAT, SMALLINT

INT8

DECIMAL, SMALLFLOAT, FLOAT, INT, SMALLINT

SERIAL

INT, INT8, DECIMAL, SMALLFLOAT, FLOAT, SMALLINT

SERIAL8

INT8, DECIMAL, SMALLFLOAT, FLOAT, INT, SMALLINT

DECIMAL

SMALLFLOAT, FLOAT, INT8, INT, SMALLINT

SMALLFLOAT

FLOAT, DECIMAL, INT8, INT, SMALLINT

FLOAT

SMALLFLOAT, DECIMAL, INT8, INT, SMALLINT

MONEY

DECIMAL, SMALLFLOAT, FLOAT, INT8, INT, SMALLINT

DATE

None

DATETIME

None

INTERVAL

None

BYTE

None

TEXT

None

Figure 2-6 shows sample overloaded test functions and a query that invokes the test function. This query invokes the function with a DECIMAL argument, test(2.0). Because a test function for a DECIMAL argument does not exist, the routine-resolution process checks for the existence of a test function for each data type shown in the precedence list in Figure 2-5.

Figure 2-6
Example of Data Type Precedence During Routine Resolution

Figure 2-6 shows the order in which the database server performs a search for the overloaded function, test(). The database server searches for a qualifying test() function that takes a single argument of type INT.

Routine Resolution with Casts

If the candidate list does not contain a routine with the same data type as an argument specified in the routine invocation, the database server might convert the argument to a different data type. The database server checks for the existence of cast routines that implicitly can convert the argument to a data type of the parameter of the candidate routines.

For example, suppose you create the following two casts and two routines:

Suppose you invoke function g with the following statement:

The database server considers both functions as candidates. The routine-resolution process selects the function g(foo,foo) because of the left-to-right rule. The database server executes the second cast, cast(bar AS foo), to convert the second argument before the function g(foo,foo) executes.

Because the database server performs implicit casts during routine resolution, a different routine than the one that the user expects might execute. For example, suppose the database has the following two routines named func():

If a user wants to invoke func(10.0) but accidentally invokes func(10), the func() routine that accepts an INT argument executes instead of the func() that accepts a DECIMAL argument. The value returned from the function for INT might corrupt the user's data.

Tip: Consider the order in which the database casts data and resolves routines as part of your decision to overload a routine.

Null Arguments in Overloaded Routines

The database server might return an error message when you call a routine and both of the following conditions are true:

Suppose you create the following functions in SPL or C language. (If the functions are external functions, you must use the HANDLESNULLS modifier to specify that each function can handle null arguments.)

The following statement creates a table, new_tab:

The following query is successful because the database server locates only one foo() function that matches the function argument in the expression:

The null value acts as a wildcard for the second argument and matches the second parameter type for each function foo() defined. The only foo() function with a leftmost parameter of type INT qualifies as the function to invoke.

If more than one qualifying routine exists, the database server returns an error. The following query returns an error because the database server cannot determine which foo() function to invoke. The null value in the first argument matches the first parameter of each function; all three foo() functions expect a second argument of type INT.

To avoid ambiguity, use null values as arguments carefully.




Extending INFORMIX-Universal Server: User-Defined Routines, version 9.1
Copyright © 1998, Informix Software, Inc. All rights reserved.