Methods
A database method of a structured type is a relationship between a set of input data values and a set of result values, where the first input value (or subject argument) has the same type, or is a subtype of the subject type (also called subject parameter), of the method.
For example, a method called CITY, of type ADDRESS, can be passed input data values of type VARCHAR, and the result is an ADDRESS (or a subtype of ADDRESS).
Methods are defined implicitly or explicitly, as part of the definition of a user-defined structured type.
Implicitly defined methods are created for every structured type. Observer methods are defined for each attribute of the structured type. Observer methods allow applications to get the value of an attribute for an instance of the type. Mutator methods are also defined for each attribute, allowing applications to mutate the type instance by changing the value for an attribute of a type instance. The CITY method described previously is an example of a mutator method for the type ADDRESS.
Explicitly defined methods, or user-defined methods, are methods that are registered to a database in SYSCAT.ROUTINES, by using a combination of CREATE TYPE (or ALTER TYPE ADD METHOD) and CREATE METHOD statements. All methods defined for a structured type are defined in the same schema as the type.
User-defined methods for structured types extend the function of the database system by adding method definitions (provided by users or third party vendors) that can be applied to structured type instances in the database engine. Defining database methods lets the database exploit the same methods in the engine that an application uses, providing more synergy between application and database.
External and SQL user-defined methods
A user-defined method can be either external or based on an SQL expression. An external method is defined to the database with a reference to an object code library and a function within that library that will be executed when the method is invoked. A method based on an SQL expression returns the result of the SQL expression when the method is invoked. Such methods do not require any object code library, because they are written completely in SQL.
A user-defined method can return a single-valued answer each time it is called. This value can be a structured type. A method can be defined as type preserving (using SELF AS RESULT), to allow the dynamic type of the subject argument to be returned as the returned type of the method. All implicitly defined mutator methods are type preserving.
Method signatures
A method is identified by its subject type, a method name, the number of parameters, and the data types of its parameters. This is called a method signature, and it must be unique within the database.
- The number of parameters or the data types of the parameters are different, or
- The methods are part of the same method hierarchy (that is, the methods are in an overriding relationship or override the same original method), or
- The same function signature (using the subject type or any of its subtypes or supertypes as the first parameter) does not exist.
A method name that has multiple method instances is called an overloaded method. A method name can be overloaded within a type, in which case there is more than one method by that name for the type (all of which have different parameter types). A method name can also be overloaded in the subject type hierarchy, in which case there is more than one method by that name in the type hierarchy. These methods must have different parameter types.
A method can be invoked by referring (in an allowable context) to the method name, preceded by both a reference to a structured type instance (the subject argument), and the double dot operator. A list of arguments enclosed in parentheses must follow. Which method is actually invoked depends on the static type of the subject type, using the method resolution process described in the following section. Methods defined WITH FUNCTION ACCESS can also be invoked using function invocation, in which case the regular rules for function resolution apply.
If function resolution results in a method defined WITH FUNCTION ACCESS, all subsequent steps of method invocation are processed.
Access to methods is controlled through the EXECUTE privilege. GRANT and REVOKE statements are used to specify who can or cannot execute a specific method or a set of methods. The EXECUTE privilege (or DATAACCESS authority) is needed to invoke a method. The definer of the method automatically receives the EXECUTE privilege. The definer of an external method or an SQL method having the WITH GRANT option on all underlying objects also receives the WITH GRANT option with the EXECUTE privilege on the method. The definer (or authorization ID with the ACCESSCTRL or SECADM authority) must then grant it to the user who wants to invoke the method from any SQL statement, or reference the method in any DDL statement (such as CREATE VIEW, CREATE TRIGGER, or when defining a constraint). If the EXECUTE privilege is not granted to a user, the method will not be considered by the method resolution algorithm, even if it is a better match.
Method resolution
After method
invocation, the database manager must decide which of the possible
methods with the same name is the best fit
. Functions (built-in
or user-defined) are not considered during method resolution.
An argument is a value passed to a method upon invocation. When a method is invoked in SQL, it is passed the subject argument (of some structured type) and a list of zero or more arguments. They are positional in that the semantics of an argument are determined by its position in the argument list. A parameter is a formal definition of an input to a method. When a method is defined to the database, either implicitly (system-generated for a type) or by a user (a user-defined method), its parameters are specified (with the subject parameter as the first parameter), and the order of their definitions defines their positions and their semantics. Therefore, every parameter is a particular positional input to a method. On invocation, an argument corresponds to a particular parameter by virtue of its position in the list of arguments.
The database manager uses the name of the method given in the invocation, EXECUTE privilege on the method, the number and data types of the arguments, all the methods with the same name for the subject argument's static type (and it's supertypes), and the data types of their corresponding parameters as the basis for deciding whether or not to select a method. The following are the possible outcomes of the decision process:
- A particular method is deemed to be the best fit. For example,
given the methods named RISK for the type SITE with signatures defined
as:
the following method invocation (where ST is a SITE column, DB is a DOUBLE column):PROXIMITY(INTEGER) FOR SITE PROXIMITY(DOUBLE) FOR SITE
then, the second PROXIMITY will be chosen.SELECT ST..PROXIMITY(DB) ...
The following method invocation (where SI is a SMALLINT column):
would choose the first PROXIMITY, because SMALLINT can be promoted to INTEGER and is a better match than DOUBLE, which is further down the precedence list.SELECT ST..PROXIMITY(SI) ...
When considering arguments that are structured types, the precedence list includes the supertypes of the static type of the argument. The best fit is the function defined with the supertype parameter that is closest in the structured type hierarchy to the static type of the function argument.
- No method is deemed to be an acceptable fit. For example, given
the same two functions in the previous case and the following function
reference (where C is a CHAR(5) column):
the argument is inconsistent with the parameter of both PROXIMITY functions.SELECT ST..PROXIMITY(C) ...
- A particular method is selected based on the methods in the type
hierarchy and the number and data types of the arguments passed on
invocation. For example, given methods named RISK for the types SITE
and DRILLSITE (a subtype of SITE) with signatures defined as:
and the following method invocation (where DRST is a DRILLSITE column, DB is a DOUBLE column):RISK(INTEGER) FOR DRILLSITE RISK(DOUBLE) FOR SITE
the second RISK will be chosen, because DRILLSITE can be promoted to SITE.SELECT DRST..RISK(DB) ...
The following method reference (where SI is a SMALLINT column):
would choose the first RISK, because SMALLINT can be promoted to INTEGER, which is closer on the precedence list than DOUBLE, and DRILLSITE is a better match than SITE, which is a supertype.SELECT DRST..RISK(SI) ...
Methods within the same type hierarchy cannot have the same signatures, considering parameters other than the subject parameter.
Determining the best fit
A comparison of
the data types of the arguments with the defined data types of the
parameters of the methods under consideration forms the basis for
the decision of which method in a group of like-named methods is the best
fit
. Note that the data types of the results of the methods under
consideration do not enter into this determination.
For method resolution, whether the data type of the input arguments can be promoted to the data type of the corresponding parameter is considered when determining the best fit. Unlike function resolution, whether the input arguments can be implicitly cast to the data type of the corresponding parameter is not considered when determining the best fit. Modules are not considered during method resolution because methods cannot be defined in modules.
Method resolution is performed using the following steps:
- First, find all methods from the catalog (SYSCAT.ROUTINES) such
that all of the following are true:
- The method name matches the invocation name, and the subject parameter is the same type or is a supertype of the static type of the subject argument.
- The invoker has the EXECUTE privilege on the method.
- The number of defined parameters matches the invocation.
- Each invocation argument matches the method's corresponding defined
parameter in data type, or is
promotable
to it.
- Next, consider each argument of the method invocation, from left
to right. The leftmost argument (and thus the first argument) is the
implicit SELF parameter. For example, a method defined for type ADDRESS_T
has an implicit first parameter of type ADDRESS_T. For each argument,
eliminate all functions that are not the best match for that argument.
The best match for a given argument is the first data type appearing
in the precedence list corresponding to the argument data type for
which there exists a function with a parameter of that data type.
Length, precision, scale, and the FOR BIT DATA attribute are not considered
in this comparison. For example, a DECIMAL(9,1) argument is considered
an exact match for a DECIMAL(6,5) parameter, a DECFLOAT(34) argument
is considered an exact match for a DECFLOAT(16) parameter, and
a VARCHAR(19) argument is an exact match for a VARCHAR(6) parameter.
The best match for a user-defined structured-type argument is itself; the next best match is its immediate supertype, and so on for each supertype of the argument. Note that only the static type (declared type) of the structured-type argument is considered, not the dynamic type (most specific type).
- At most, one candidate method remains after Step 2. This is the method that is chosen.
- If there are no candidate methods remaining after step 2, an error is returned (SQLSTATE 42884).
Example of method resolution
Following is an example of successful method resolution.
CREATE METHOD FOO (CHAR(5), INT, DOUBLE) FOR HEADOFSTATE SPECIFIC FOO_1 ...
CREATE METHOD FOO (INT, INT, DOUBLE) FOR HEADOFSTATE SPECIFIC FOO_2 ...
CREATE METHOD FOO (INT, INT, DOUBLE, INT) FOR HEADOFSTATE SPECIFIC FOO_3 ...
CREATE METHOD FOO (INT, DOUBLE, DOUBLE) FOR EMPEROR SPECIFIC FOO_4 ...
CREATE METHOD FOO (INT, INT, DOUBLE) FOR EMPEROR SPECIFIC FOO_5 ...
CREATE METHOD FOO (SMALLINT, INT, DOUBLE) FOR EMPEROR SPECIFIC FOO_6 ...
CREATE METHOD FOO (INT, INT, DEC(7,2)) FOR GOVERNOR SPECIFIC FOO_7 ...
SELECT E..FOO(I1, I2, D) ...
Following
through the algorithm... - FOO_7 is eliminated as a candidate, because the type GOVERNOR is a subtype (not a supertype) of EMPEROR.
- FOO_3 is eliminated as a candidate, because it has the wrong number of parameters.
- FOO_1 and FOO_6 are eliminated because, in both cases, the first argument (not the subject argument) cannot be promoted to the data type of the first parameter. Because there is more than one candidate remaining, the arguments are considered in order.
- For the subject argument, FOO_2 is a supertype, while FOO_4 and FOO_5 match the subject argument.
- For the first argument, the remaining methods, FOO_4 and FOO_5, are an exact match with the argument type. No methods can be eliminated from consideration; therefore the next argument must be examined.
- For this second argument, FOO_5 is an exact match, but FOO_4 is not, so it is eliminated from consideration. This leaves FOO_5 as the method chosen.
Method invocation
Once the method is selected, there are still possible reasons why the use of the method may not be permitted.
STEP(SMALLINT) FOR TYPEA RETURNS CHAR(5)
STEP(DOUBLE) FOR TYPEA RETURNS INTEGER
and the following
method reference (where S is a SMALLINT column and TA is a column
of TYPEA): SELECT 3 + TA..STEP(S) ...
then,
because there is an exact match on argument type, the first STEP is
chosen. An error occurs on the statement, because the result type
is CHAR(5) instead of a numeric type, as required for an argument
of the addition operator.Starting from the method that has
been chosen, the algorithm described in Dynamic dispatch of methods
is
used to build the set of dispatchable methods at compile time. Exactly
which method is invoked is described in Dynamic dispatch of methods
.
- the static result type following function resolution is the same as the static type of the subject argument of the method invocation
- the dynamic result type when the method is invoked is the same as the dynamic type of the subject argument of the method invocation.
In cases where the arguments of the method invocation were not an exact match to the data types of the parameters of the selected method, the arguments are converted to the data type of the parameter at execution using the same rules as assignment to columns. This includes the case where precision, scale, or length differs between the argument and the parameter, but excludes the case where the dynamic type of the argument is a subtype of the parameter's static type.
Dynamic dispatch of methods
Methods provide the functionality and encapsulate the data of a type. A method is defined for a type and can always be associated with this type. One of the method's parameters is the implicit SELF parameter. The SELF parameter is of the type for which the method has been declared. The argument that is passed as the SELF argument when the method is invoked in a DML statement is called subject.
When a method is chosen using method resolution (see Method resolution), or a method has been specified
in a DDL statement, this method is known as the most specific applicable
authorized method
. If the subject is of a structured type, that
method could have one or more overriding methods. A determination
is then made to select which method to invoke, based on the dynamic
type (most specific type) of the subject at run time. This determination
is called determining the most specific dispatchable method
.
That process is described here.
- Find the original method in the method hierarchy that the most specific applicable authorized method is part of. This is called the root method.
- Create the set of dispatchable methods, which includes the following:
- The most specific applicable authorized method.
- Any method that overrides the most specific applicable authorized method, and which is defined for a type that is a subtype of the subject of this invocation.
- Determine the most specific dispatchable method, as follows:
- Start with an arbitrary method that is an element of the set of dispatchable methods and that is a method of the dynamic type of the subject, or of one of its supertypes. This is the initial most specific dispatchable method.
- Iterate through the elements of the set of dispatchable methods. For each method: If the method is defined for one of the proper subtypes of the type for which the most specific dispatchable method is defined, and if it is defined for one of the supertypes of the most specific type of the subject, then repeat step 2 with this method as the most specific dispatchable method; otherwise, continue iterating.
- Invoke the most specific dispatchable method.
Example:
Given are three types, "Person", "Employee", and "Manager". There is an original method "income", defined for "Person", which computes a person's income. A person is by default unemployed (a child, a retiree, and so on). Therefore, "income" for type "Person" always returns zero. For type "Employee" and for type "Manager", different algorithms have to be applied to calculate the income. Hence, the method "income" for type "Person" is overridden in "Employee" and "Manager".
CREATE TABLE aTable (id integer, personColumn Person);
INSERT INTO aTable VALUES (0, Person()), (1, Employee()), (2, Manager());
List
all persons who have a minimum income of $40000: SELECT id, person, name
FROM aTable
WHERE person..income() >= 40000;
The method "income" for type "Person" is chosen, using method resolution, to be the most specific applicable authorized method.
- The root method is "income" for "Person" itself.
- The second step of the previous algorithm is carried out to construct
the set of dispatchable methods:
- The method "income" for type "Person" is included, because it is the most specific applicable authorized method.
- The method "income" for type "Employee", and "income" for "Manager" is included, because both methods override the root method, and both "Employee" and "Manager" are subtypes of "Person".
Therefore, the set of dispatchable methods is: {"income" for "Person", "income" for "Employee", "income" for "Manager"}.
- Determine the most specific dispatchable method:
- For a subject whose most specific type is "Person":
- Let the initial most specific dispatchable method be "income" for type "Person".
- Because there is no other method in the set of dispatchable methods that is defined for a proper subtype of "Person" and for a supertype of the most specific type of the subject, "income" for type "Person" is the most specific dispatchable method.
- For a subject whose most specific type is "Employee":
- Let the initial most specific dispatchable method be "income" for type "Person".
- Iterate through the set of dispatchable methods. Because method "income" for type "Employee" is defined for a proper subtype of "Person" and for a supertype of the most specific type of the subject (Note: A type is its own super- and subtype.), method "income" for type "Employee" is a better match for the most specific dispatchable method. Repeat this step with method "income" for type "Employee" as the most specific dispatchable method.
- Because there is no other method in the set of dispatchable methods that is defined for a proper subtype of "Employee" and for a supertype of the most specific type of the subject, method "income" for type "Employee" is the most specific dispatchable method.
- For a subject whose most specific type is "Manager":
- Let the initial most specific dispatchable method be "income" for type "Person".
- Iterate through the set of dispatchable methods. Because method "income" for type "Manager" is defined for a proper subtype of "Person" and for a supertype of the most specific type of the subject (Note: A type is its own super- and subtype.), method "income" for type "Manager" is a better match for the most specific dispatchable method. Repeat this step with method "income" for type "Manager" as the most specific dispatchable method.
- Because there is no other method in the set of dispatchable methods that is defined for a proper subtype of "Manager" and for a supertype of the most specific type of the subject, method "income" for type "Manager" is the most specific dispatchable method.
- For a subject whose most specific type is "Person":
- Invoke the most specific dispatchable method.