This chapter describes how to define function instances.
Functions and operators (jointly referred to in this chapter as "functions") can be used in many contexts. For example, you can use the operator "+" to add numbers, concatenate strings, or to add two user-defined data type values. The use of a function within a given context is called a function instance.
The definition of a function instance links a function definition and the function's arguments to a procedure (user-written executable procedure, not a database procedure) and a result (type and length). For every new function that you define, you must provide the DBMS Server with function instance definitions for its use. You must also provide the function instance definitions that define the use of your new data type with the functions with which you intend to use it.
Function instances are defined by filling in the structure IIADD_FI_DFN, once for each instance. IIADD_FI_DFN is included in the header file provided with Object Management Extension. The fields in this structure are as follows:
Must contain the constant II_O_FUNCTION_INSTANCE.
Must contain a valid function instance identifier. This is a 2-byte integer, starting at 16384 (II_FISTART). The DBMS Server uses this number internally to identify the function instance.
If you have defined fid_type as II_COMPARISON, this field must contain the fid_opid of this function instance's complement. For more information, see Complementary Function Instances.
Contains the function identifier used to invoke this function instance. The function id can be a constant identifying a standard SQL operator or the identifier of a new function that was defined using the IIADD_FO_DFN structure.
If the function instance that you are defining is a data type coercion (that is, fid_optype = II_COERCION), this value must be II_NOOP.
Contains the operation type invoked by the operator. The legal values for this field are:
II_COMPARISON
II_OPERATOR
II_NORMAL
II_COERCION
Specifies how the function instance behaves.
II_FID_F0_NOFLAGS
II_FID_F4_WORKSPACE
II_FID_F8_INDIRECT
Specifies the length of the workspace. Valid only if II_FID_F4_WORKSPACE is set.
Number of arguments for this function. The fid_numargs field is a 4-byte integer. Values in this field are related to the values in the fid_optype field. If fid_optype is II_COMPARISON or II_OPERATION, this value must be 2. If it is II_COERCION, this value must be 1. If fid_optype is II_NORMAL, fid_numargs can be 0, 1, or 2.
Pointer to an array of data types, which are the data types of the arguments for the function instance. Each array element is a 2-byte integer. The first element in the array must point to the first argument, the second element to the second argument, and so on. If the function instance has no arguments, set this pointer to 0.
The proprietary Ingres data types, date and money are not currently supported for user manipulation.
The specified argument data types can be user-defined data types or standard SQL data types. To specify a user-defined data type, use the value in the dtd_id field of the IIADD_DT_DFN structure for that data type. To specify a data type, use one of the following values:
II_INTEGER
II_FLOAT
II_CHAR
II_C
II_VARCHAR
II_TEXT
II_LONGTEXT
To specify a spatial data type, use the following values:
PNT_TYPE
BOX_TYPE
LSEG_TYPE
LINE_TYPE
POLY_TYPE
CIRCLE_TYPE
LLINE_TYPE
LPOLY_TYPE
IPNT_TYPE
IBOX_TYPE
ILSEG_TYPE
ILINE_TYPE
IPOLY_TYPE
ICIRCLE_TYPE
NBR_TYPE
The data type of the function instance result.
Set this field to one of the following values to specify the method used to determine the length of the function instance's result. Note that the arguments referred to are the arguments to the routines that perform the operation defined by the function instance. Valid values:
II_RES_FIXED
II_RES_FIRST
II_RES_SECOND
II_RES_LONGER
II_RES_SHORTER
II_RES_KNOWN
II_RES_EXTERN
Set this field to the length of the function instance's result if the fid_rltype field is II_RES_FIXED. Otherwise, set this field to II_LEN_UNKNOWN (-1).
Precision of the data value. For most data types, this is not needed and should be set to 0. However, for DECIMAL, the high order byte will represent the value's precision (total number of significant digits), and the low order byte will hold the value's scale (the number of these digits that are to the right of an implied decimal point). Calculate this value and set accordingly.
Address of the routine that performs the function instance.
Address of the routine that can be called to compute the result length.
The length of a result data type is defined by fid_rlength in II_ADD_FI_DFN or an external lenspec routine. This length is used by the DBMS Server when manipulating values internally. The length component of the actual data value (II_DATA_VALUE db_length) should not be changed within the function itself. If the length defined by fid_rlength or the lenspec routine differs from the data value's db_length, then errors may result or data values may be incorrectly interpreted.
The same is true of scale and precision in the case of DECIMAL. In this case, the fid_rprec or lenspec is used and the db_prec of the data value should not be changed.
The following macros, defined in $II_SYSTEM/ingres/files/iiadd.h, can be used to manipulate DECIMAL length values:
Given a precision p and scale s, returns the two-byte value combining the two. This macro could be used, for example, when setting db_prec value within a user-defined lenspec routine.
Given a two-byte combined value for precision and scale (db_prec) of ps, returns the precision part.
Given a two-byte combined value for precision and scale (db_prec) of ps, returns the scale part.
Given a precision of prec, returns the length needed for such a decimal. This macro could be used when setting the db_length within a user-defined lenspec routine.
The lenspec routine returns the result length for the specified value in the db_length field of the dvr parameter. This routine is called by the DBMS Server when a function instance's fid_rltype field is set to II_RES_EXTERN. Lenspec also returns II_STATUS.
The parameters for the lenspec routine are as follows:
Points to the session control block for error processing.
Points to the operator being invoked.
Pointers to II_DATA_VALUE. These pointers specify the inputs to the operator. If the function instance does not use one of the operands, that pointer is zero.
Pointer to an II_DATA_VALUE whose length is filled in by this routine.
The II_DATA_VALUE parameters are used only to pass type and length information. The db_data field in the II_DATA_VALUE structure must be ignored.
To optimize query performance, the DBMS Server often inverts the sense of a comparison operation. To make this possible, you must define a complementary function instance for every function instance of fid_optype II_COMPARISON that you define.
For example, if you define a function instance for the equals (=) operator, you must also define a function instance for its complement, not equals (!=). Note that the complement of ">=" is "<", and the complement of "<=" is ">".
Complementing function instance definitions must agree. That is, if A is a function instance whose complement is B (A's fid_cmplmnt = B's fid_opid), the complement of B must be A (B's fid_cmplmnt = A's fid_opid).
For the DBMS Server to merge the new function instance definitions with existing function instance definitions, the array of function instance definitions that you create must be specified in sorted order.
The array must be sorted by the number value of the fid_optype field. All comparisons (fid_optype = II_COMPARISON) must be first, followed by all operators (fid_optype = II_OPERATOR), normal functions (fid_type = II_NORMAL), and finally, the coercion functions (fid_optype = II_COERCION).
In each operator type, sort the function instances by the numeric value of the fid_opid field. For example, with the operator type II_COMPARISON, the function instances are sorted in the following order:
Object Management Extension provides two ways to define function instances for large objects. You can use the Ingres-supplied filter functions or you can manipulate the large objects directly.
Of the callback functions, two have been paired to allow for function instances that must traverse a large object. Ingres provides skeleton code that allows you to pass the object through your filter.
To use a filter function, the calling instance sets up the workspace by calling the function supplied to initialize the workspace. This function does all the work necessary to allow for the simple traversal of the input object. After this, your filter function is called for each segment and is passed an II_DATA_VALUE, which provides space for manipulation of the input and output segments, a function to call for each segment, a workspace to be used by this routine, and a continuation indicator.
The continuation indicator states whether this is the first or last call to the filter. The indicator is specified by the use of the II_C_BEGIN_MASK and the II_C_END_MASK, indicating that this is the beginning or end of the resulting object.
The function to be called is called with pointers to II_DATA_VALUE, which describes input and output segments. The routine is expected to convert the input into the output segment. When processing the data, the function indicates the disposition of the current segment by filling in the value of the adw_shared.shd_exp_action field of the workspace.
As the routine moves through the object, it is expected to keep the adw_shared.shd_l1_chk field filled with the current length of the large object that is the result. The routine that is called back does not necessarily know if it will be called again.
The expected action indicator conveys information between the filter routine and the function instance routine. The indicator is set to ADW_START before the first segment routine call. Thereafter, the indicator is examined at the return of the call to determine the next action necessary for the function instance routine to perform.
The possible values and responses are as follows:
The calling routine disposes of the current segment, get a new segment, and recall the routine.
The function instance routine obtains the next segment of data to be processed by the routine. The output segment remains unchanged.
The function instance routine is expected to dispose of the current (presumably "full") output segment, and provide a new, empty one for the routine to deal with. The input segment is untouched.
The function flushes the current segment and stop.
The routine stops without flushing the current output segment.
If the routine returns ADW_GET_DATA and there is no more data to get, the function instance routine disposes of the current segment and assumes that the work of the routine is complete. The routine is not called again.
This calling sequence means that the routine never knows if it will be called again. For this reason, the adw_l0_chk and adw_l1_chk values must be correct, and the output segment from your filter must always be a valid segment, even when the filter is not complete.
Of the fields in the workspace, only those in the shared section are interpreted by the filter function. The shd_exp_action, shd_l0_chk, and shd_l1_chk fields must be set as described above. The other fields in the II_SHARED structure must be left unchanged.
The remaining fields in the workspace are available for each function instance's use.
In some cases, (for example, two-pass algorithms,) defining a function instance does not work. For these situations, your code can get the peripheral object segments directly through the use of the large object handler. The handler routine performs a variety of operations on large objects.
The handler is called with two arguments. The first is the operation code, which tells the handler which operation to perform. The second argument is a peripheral object control block, II_POP_CB. This control block structure is used to pass information to and from the caller of the handler. The first part of this structure is a standard header used in the DBMS Server.
The exact description of this control block structure can be found in the iiadd.h header file.
The pop_type field must always be set to II_POP_TYPE. The pop_length field must always be set to the size of the structure. The pop_s_reserved and pop_l_reserved fields must not be set or altered. These fields are used by the DBMS Server memory management routines. You can set the other fields as required.
The rest of the II_POP_CB control block consists of the following fields:
The err_code field of this structure contains any error that results from the requested operation. The II_E_NOMORE error indicates that there are no more segments to get. Other errors indicate coding errors.
Tells the handler routine whether this is the first and/or last invocation of this routine. The use of this field varies by function (refer to the operations that follow for specific use). This field is a mask, so a single operation can be the first (II_C_BEGIN_MASK), the last (II_C_END_MASK), neither (0), or both (II_C_BEGIN_MASK | II_C_END_MASK).
Indicates the lifetime of the object being created (through an II_PUT operation). A value of II_POP_SHORT_TEMP indicates that the object must be destroyed at the end of the current query. There are no other valid values.
Contains information about the underlying data type for the operation. The underlying data type describes the segment being manipulated. The field is partially filled in by the caller (db_datatype) and partially by the II_INFORMATION operation (db_length). Because the length allowed can change in future releases of the software, using the information operation as described aids in upward compatibility. The db_data field is unused.
Pointers to II_DATA_VALUES that describe the overall object (the pop_coupon field) being manipulated, and the individual segment being worked on (pop_segment).
Provided for the handler's use. This field must not be touched by your code between the first and last call in a series to the handler (that is, between the II_C_BEGIN_MASK instance and the II_C_END_MASK instance). The handler uses this field to maintain a context. This is necessary due to the multi-threaded nature of the DBMS Server.
This operation returns the maximum length (in bytes) for each segment of a peripheral object.
The input fields for the II_INFORMATION operation are the parts of the peripheral control block structure that tell the DBMS Server what information to pass and how to pass the information. The inputs are as follows:
The value of II_INFORMATION
A pointer to the peripheral operations control block, II_POP_CB (for calling).
The coupon about which the information is required.
The output fields for the II_INFORMATION operation describe the results the DBMS Server returns. The outputs are as follows:
A pointer to the peripheral operations control block, II_POP_CB (for calling).
Maximum length for underlying portions of the data type.
The DBMS Server fills this field with the error value, if there is any.
II_STATUS
This operation gets the next segment of some object. The object is represented to II_GET by a coupon. This operation makes use of the saved information in the peripheral control block, which is passed in the pop_cb's user argument parameter.
The input fields for the II_GET operation are the parts of the peripheral control block structure that tell the DBMS Server what and how to pass the information. The inputs are as follows:
The value of II_GET.
A pointer to the peripheral operations control block, II_POP_CB (for calling).
Continuation indicator. On the first call II_C_BEGIN_MASK is passed; otherwise, zero (0) is passed.
Pointer to II_DATA_VALUE, contains the coupon used to retrieve the object.
Pointer to II_DATA_VALUE to receive the output of II_GET. An error occurs if the size of the output is insufficient. For size determination, see II_INFORMATION Operation.
Server's internal state. This is set on the first call and must be presented unchanged for subsequent calls.
The output fields for the II_GET operation describe the results the DBMS Server returns. The outputs are as follows:
A pointer to the peripheral operations control block, II_POP_CB (for calling).
The DBMS Server fills this field with the next segment.
The DBMS Server fills this field, if appropriate.
The DBMS Server fills this field with the error value, if there is any.
II_STATUS
This operation adds a new segment to the end of a new peripheral object. This operation takes, as input, the segments of a peripheral object, and returns a completed coupon. When there are multiple segments in an object, the coupon is not complete until the last invocation of the II_PUT operation.
The underlying data type must be provided by the caller, and describes how the underlying data must be represented. See the pop_underdv field in the table below. For example, long varchar objects are stored as varchar segments.
The input fields for the II_PUT operation are the parts of the peripheral control block structure that tell the DBMS Server what and how to pass the information. The inputs are as follows:
The value of II_PUT.
A pointer to the peripheral operations control block, II_POP_CB (for calling).
Indicates the state of the object. On the first call of a multicall operation, II_C_BEGIN_MASK is set. On the last call, II_C_END_MASK is set. A single call can be either the first call, last call, both, or neither.
Pointer to the coupon to be created.
A pointer to a data area from which data is taken (to be put into the large object).
A pointer to a II_DATA_VALUE that describes the data type to be used for each segment.
Must be II_POP_SHORT_TEMP.
Workspace area used by the server. The caller knows nothing of the contents here, but is expected to preserve its contents across multipass calls. Failure to do so results in errors.
The output fields for the II_PUT operation describe the results returned by the DBMS Server. The outputs are as follows:
A pointer to the peripheral operations control block, II_POP_CB (for calling).
For temporaries, are completely filled. This portion cannot be complete until the last call of a multipass operation is completed.
Is filled in with server specific information to be preserved and returned by the caller if II_PUT is not a coupon and pop_continuation is not II_C_END_MASK.
The DBMS Server fills this field with the error value, if there is any.
II_STATUS
This operation moves a peripheral object by performing gets and puts.
The input fields for the II_COPY operation are the parts of the peripheral control block structure that tell the DBMS Server what and how to pass the information. The inputs are as follows:
The value of II_COPY.
A pointer to the peripheral operations control block, II_POP_CB (for calling).
A pointer to the input object. In this case, pop_segment and the input object are both coupons.
A pointer to an II_DATA_VALUE that describes the area to be filled with the coupon for the copied object.
The output fields for the II_COPY operation describe the results returned by the DBMS Server. The outputs are as follows:
A pointer to the peripheral operations control block, II_POP_CB (for calling).
The DBMS Server fills this field with the coupon for the copied object.
The DBMS Server fills this field with the error value, if there is any.
II_STATUS