![]() |
|
Home | Contents | Index | Master Index | New Book | ![]() |
![]() |
SPL StatementsIn This ChapterYou can use Stored Procedure Language (SPL) statements to write routines, and you can store these SPL routines in the database. These SPL routines are effective tools for controlling SQL activity.This chapter contains descriptions of the SPL statements. The description of each statement includes the following information:
For task-oriented information about using SPL routines, see Chapter 14 of the Informix Guide to SQL: Tutorial.
UsageThe CALL statement invokes one of the following:
If you use CALL with a procedure name, you cannot specify a RETURNING clause. If you use CALL with a function name, you must specify a RETURNING clause.
When you use CALL to execute a routine, you have the option of specifying parameter names for the arguments you pass to the routine. For example, each of the following examples is valid for a routine that has three parameters of VARCHAR type, named t, n, and d, in that order: The syntax of specifying arguments is described in more detail in the Argument segment on page 1-828.
The following example shows two routine calls. One routine call is to a procedure (no_args), which expects no returned values. The second routine call is to a function (yes_args), which expects three returned values. The not_much() procedure declares three integer variables (i, j, and k) to receive the returned values from yes_args.
UsageWhen you encounter a CONTINUE statement, the routine skips the rest of the statements in the innermost loop of the indicated type. Execution continues at the top of the loop with the next iteration. In the following example, the SPL function loop_skip inserts values3 through 15 into the table testtable. The function also returns values 3 through 9 and 13 through 15 in the process. The function does not return the value 11, because it encounters the CONTINUE FOR statement. The CONTINUE FOR statement causes the function to skip the RETURN i WITH RESUME statement.The CONTINUE statement generates errors if it cannot find the identified loop.
UsageThe DEFINE statement is not an executable statement. It must appear after the routine header and before any other statements.If you define a local variable (by using DEFINE without the GLOBAL keyword), the scope of the variable is the statement block in which it is defined. You can use the variable anywhere within the statement block. You can also use the same variable name outside the statement block with a different definition. If you define a variable with the GLOBAL keyword, the variable is global in scope and is available outside the statement block and to other routines.
Variables of INT data type hold data from SERIAL columns, and variables of INT8 data type hold data from SERIAL8 columns.
You cannot define a variable that references a CLOB or BLOB data type.
Routines that are running in the current session share global variables. Because the database server does not save global variables in the database, the global variables do not remain when the current session closes. The data types of global variables you use in your SPL routine must match the data types of variables in the global environment. Databases do not share global variables. The database server does not share global variables with application development tools. The first declaration of a global variable establishes the variable in the global environment. Subsequent global declarations simply bind the variable to the global environment and establish the value of the variable at that point. The following example shows two SPL procedures, proc1 and proc2. Each procedure has defined the global variable gl_out: If proc1 is called first, gl_out is set to 13 and then incremented to 14 . If proc2 is then called, it sees that the value of gl_out is already defined, so the default value of 23 is not applied. Then, proc2 assigns the existing value of 14 to tmp. If proc2 had been called first, gl_out would have been set to 23 , and 23 would have been assigned to tmp. Later calls to proc1 would not apply the default of 13 .
SITENAME or DBSERVERNAMEIf you use the value returned by SITENAME or DBSERVERNAME as the default, the variable must be a CHAR, VARCHAR, NCHAR, or NVARCHAR value of at least 18 characters.
TODAYIf you use TODAY as the default, the variable must be a DATE value.
Declaring Local VariablesMost local variables (that is, nonglobal variables) do not allow defaults. The following example shows typical definitions of local variables:
Declaring Collection VariablesA variable of type COLLECTION, SET, MULTISET, and LIST is a collection variable and holds a collection fetched from the database. You cannot define a collection variable as global (with the GLOBAL keyword) or with a default value.A variable defined with the type COLLECTION is an untyped collection variable. An untyped collection variable is generic and can hold a collection of any type. A variable defined with the type SET, MULTISET, or LIST is a typed collection variable. A typed collection variable can hold only a collection of its type. You must define the elements of a typed collection variable as NOT NULL, as in the following examples: Note that with variable c, both the INTEGER values in the SET and the SET values in the LIST are defined as NOT NULL. You can define collection variables with nested complex types to hold matching nested complex type data. Any type or depth of nesting is allowed. You can nest row types within collection types, collection types within row types, collection types within collection types, s within collection and row types, and so on. If you define a variable of COLLECTION type, the variable acquires varying type assignments if it is reused within the same statement block, as in the following example: In this example, varA is a generic collection variable that changes its data type to the data type of the currently assigned collection. The first LET statement makes varA a SET variable. The second LET statement makes varA a LIST variable.
A generic row variable, defined with the ROW keyword, can hold data from any row type. A named row variable holds data from the specific named row type specified in the variable definition. The following statements show examples of generic row variables and named row variables: A named row variable holds named row types of the same type in the variable definition. To define a variable that will hold data stored in an unnamed row type, use the ROW keyword followed by the fields of the row type, as in: Unnamed row types are type-checked only by structural equivalence. Two unnamed row types are considered equivalent if they have the same number of fields, and if the fields have the same type definitions. Therefore, you could fetch either of the following row types into the variable area defined above: Row variables can have fields, just as row types have fields. To assign a value to a field of a row variable, use the SQL dot notation variableName.fieldName, followed by an expression, as in the following example:
When you assign a value to a row variable, you can use any allowed expression described in "Expression".Declaring Opaque-Type VariablesOpaque type variables hold data retrieved from opaque types, which you create with the CREATE OPAQUE TYPE statement. An opaque type variable can only hold data of the opaque type on which it is defined.The following example defines a variable of the opaque type point, which holds the x and y coordinates of a two-dimensional point:
Declaring Variables Like ColumnsIf you use the LIKE clause, the database server gives SPL variable the same data type as a column in a table, synonym, or view.The data types of variables that are defined as database columns are resolved at runtime. Therefore, column and table do not need to exist at compile time.
Defining a variable of PROCEDURE type indicates that in the current statement scope, SPL variable is not a call to an SQL function or a system function. For example, the following statement defines length as an SPL routine, not as the SQL LENGTH function: This definition disables the SQL LENGTH function within the scope of the statement block. You would use such a definition if you had already created an SPL routine or an external routine with the name length. If you create a routine with the same name as an aggregate function (SUM, MAX, MIN, AVG, COUNT) or with the name extend, you must qualify the routine name with the owner name.
The following example defines a local BYTE variable: If you pass a variable of TEXT or BYTE data type to an SPL routine, the data is passed to the database server and stored in the root dbspace or dbspaces that the DBSPACETEMP environment variable specifies, if it is set. You do not need to know the location or name of the file that holds the data. BYTE or TEXT manipulation requires only the name of the BYTE or TEXT variable as it is defined in the routine. You cannot declare a variable to hold or reference a CLOB or BLOB data type.
The database server allows the redeclaration in the following example. Within the nested statement block, n is a character variable. Outside the block, n is an integer variable.
EXITUse the EXIT statement to stop the execution of a FOR, WHILE, or FOREACH loop.
UsageThe EXIT statement causes the innermost loop of the indicated type (FOR, WHILE, or FOREACH) to terminate. Execution resumes at the first statement outside the loop.If the EXIT statement cannot find the identified loop, it fails. If the EXIT statement is used outside all loops, it generates errors.
The following example uses an EXIT FOR statement. In the FOR loop, when
FORUse the FOR statement to initiate a controlled (definite) loop when you want to guarantee termination of the loop. The FOR statement uses expressions or range operators to establish a finite number of iterations for a loop.
The FOR loop terminates when variable name takes on the values of each element in the expression list or range in succession or when it encounters an EXIT FOR statement. The database server generates an error if an assignment within the body of the FOR statement attempts to modify the value of variable name.
If you omit the STEP option, the database server gives increment expression the value of -1 if right expression is less than left expression, or +1 if right expression is more than left expression. If increment expression is specified, it must be negative if right expression is less than left expression, or positive if right expression is more than left expression. The two statements in the following example are equivalent. In the first statement, the STEP increment is explicit. In the second statement, the STEP increment is implicitly 1 .The database server initializes the value of variable name to the value of left expression. In subsequent iterations, the server adds increment expression to the value of variable name and checks increment expression to determine whether the value of variable name is still between left expression and right expression. If so, the next iteration occurs. Otherwise, an exit from the loop takes place. Or, if you specify another range, the variable takes on the value of the first element in the next range.
Using an Expression List as the RangeThe database server initializes the value of variable name to the value of the first expression specified. In subsequent iterations, variable name takes on the value of the next expression. When the server has evaluated the last expression in the list and used it, the loop stops.The expressions in the IN list do not have to be numeric values, as long as you do not use range operators in the IN list. The following example uses a character expression list: The following FOR statement shows the use of a numeric expression list:
Mixing Range and Expression Lists in the Same FOR StatementIf variable name is an INT or SMALLINT value, you can mix ranges and expression lists in the same FOR statement. The following example shows a mixture that uses an integer variable. Values in the expression list include the value that is returned from a SELECT statement, a sum of an integer variable and a constant, the values that are returned from an SPL procedure named p_get_int, and integer constants.
FOREACHUse a FOREACH loop to select and handle a set of rows or a collection.
UsageA FOREACH loop is the procedural equivalent of using a cursor. When Universal Server executes a FOREACH statement, it takes the following actions:
1. It declares and implicitly opens a cursor. 4. It executes the statement block. 5. It fetches the next row, the next collection element, or the next set of return values, and it repeats steps 3 and 4. An SPL routine that returns more than one row, collection element, or set of values is called a cursor routine. An SPL routine that returns only one row or value is a noncursor routine. The following SPL procedure illustrates the three types of FOREACH statements: with a SELECT...INTO clause, with an explicitly named cursor, and with a procedure call: A select cursor is closed when any of the following situations occur:
Using a SELECT...INTO StatementWith an ordinary cursor that fetches a set of rows or values, you can use a SELECT ... INTO statement. With an ordinary cursor, SELECT ... INTO can also include the UNION and ORDER BY clauses, but it cannot include the INTO TEMP clause. The syntax of a SELECT statement is shown on page 1-596.The type and count of each variable in the variable list must match each value that the SELECT...INTO statement returns.
In this example, the SELECT statement within the FOREACH loop is the collection query. The statement selects one element at a time from the collection variable b into the element variable a. In the collection query, the select field list is an asterisk, because the collection variable b contains a collection of built-in types. The variable b is used with the TABLE keyword as a Collection Derived Table. For more information on using a Collection Derived Table, see page 1-831. The next example shows a collection query that uses a list of row type fields in its select field list. In this example, the collection variable employees contains a collection of row types. Each row type contains the fields name and salary. The collection query selects one name and salary combination at a time, placing name into n and salary into s. The AS keyword names e as an alias for the collection derived table employees. The alias exists as long as the SELECT statement executes. To update an element of a collection, you must first declare a cursor with the FOREACH statement. Then, within the FOREACH loop, select elements one at a time from the collection variable, using the collection variable as a Collection Derived Table in a SELECT query. For more information on selecting from a collection variable, see the SELECT statement on page 1-596. When the cursor is positioned on the element to be updated, you can use the WHERE CURRENT OF clause, as follows:
Calling a Routine in the FOREACH LoopIn general, use the following guidelines for calling another routine from an SPL routine:
If you use EXECUTE FUNCTION, Universal Server looks for a function of the name you specify. If it does not find a function of that name, the server issues an error message. A called function can return zero or more values or rows. The type and count of each variable in the variable list must match each value that the function returns.
UsageThe condition that the IF clause states is evaluated. If the result is true, the statements that follow the THEN keyword execute. If the result is false, and an ELIF clause exists, the statements that follow the ELIF clause execute. If no ELIF clause exists, or if the condition in the ELIF clause is not true, the statements that follow the ELIF keyword execute.
In the following example, the SPL function uses an IF statement with both an ELIF clause and an ELSE clause. The IF statement compares two strings and displays a
The ELIF ClauseUse the ELIF clause to specify one or more additional conditions to evaluate.If you specify an ELIF clause, and the IF condition is false, the ELIF condition is evaluated. If the ELIF condition is true, the statements that follow the ELIF clause execute.
If any expression that the condition contains evaluates to null, the condition automatically becomes untrue. Consider the following points:
You can use a SELECT statement only if you use the INTO TEMP clause to put the results of the SELECT statement into a temporary table.
UsageIf you assign a value to a single variable, you make a simple assignment. If you assign values to two or more variables, you make a compound assignment.You can also assign the value of an expression to a variable. At runtime, the value of the SPL expression is computed first. The resulting value is cast to the data type of variable, if possible, and the assignment occurs. If conversion is not possible, an error occurs, and the value of variable name is undefined. A compound assignment assigns multiple expressions to multiple variables. The data types of expressions in the expression list does not need to match the data types of the corresponding variables in the variable list, because the database server automatically converts the data types. (For a detailed discussion of casting, see the Informix Guide to SQL: Syntax.) The following example shows several LET statements that assign values to SPL variables: You cannot use multiple values to operate on other values. For example, the following statement is illegal:
Using a SELECT Statement in a LET StatementThe examples in this section use a SELECT statement within a LET statement. You can use a SELECT statement to assign values to one or more variables on the left side of the = operator, as the following examples show:You cannot use a SELECT statement to make multiple values operate on other values. The following example is illegal: Because a LET statement is equivalent to a SELECT...INTO statement, the two statements in the following example have the same results, a=c and b=d: If the SELECT statement returns more than one row, you must enclose the SELECT statement in a FOREACH loop For more information on FOREACH, see page 2-27.
If you name one of the parameters in the called function, with syntax such as name = 'smith', you must name all the parameters. The named variable receives the returned value from a function call. A function can return more than one value into a list of variable names. However, you must enclose a function that returns more than one value in a FOREACH loop. The following example shows several LET statements. The first two are valid LET statements that contain function calls. The third LET statement is not legal, because it tries to add the output of two functions and then assign the sum to two variables, a and b. You can easily split this LET statement into two legal LET statements. A function called in a LET statement can have an argument of COLLECTION, SET, MULTISET, or LIST. COLLECTION is a generic collection data type that includes SET, MULTISET, and LIST collection types. You can then assign the value returned by the function to a variable, for example: In the first statement, the SPL function function1 accepts collection1 (that is, any collection data type) as an argument and returns its value to the variable d. In the second statement, the SPL function function2 accepts set1 as an argument and returns a value to the variable a.
UsageThe ON EXCEPTION statement, together with the RAISE EXCEPTION statement, provides an error-trapping and error-recovery mechanism for SPL. The ON EXCEPTION statement defines a list of errors that are to be trapped as the SPL routine executes and specifies the action (within the statement block) to take when the trap is triggered. If the IN clause is omitted, all errors are trapped.You can use more than one ON EXCEPTION statement within a given statement block. The scope of an ON EXCEPTION statement is the statement block that follows the ON EXCEPTION statement, all the statement blocks that are nested within that following statement block, and all the statement blocks that follow the ON EXCEPTION statement. The exceptions that are trapped can be either system- or user-defined. When an exception is trapped, the error status is cleared. If you specify a variable to receive an ISAM error, but no accompanying ISAM error exists, a zero returns to the variable. If you specify a variable to receive the returned error text, but none exists, an empty string goes into the variable.
The following example shows the correct placement of an ON EXCEPTION statement. Use an ON EXCEPTION statement after the DEFINE statement and before the body of the routine. The following SPL function inserts a set of values into a table. If the table does not exist, it is created, and the values are inserted. The SPL function also returns the total number of rows in the table after the insert occurs. When an error occurs, the database server searches for the last declaration of the ON EXCEPTION statement, which traps the particular error code. The ON EXCEPTION statement can have the error number in the IN clause or have no IN clause. If the database server finds no pertinent ON EXCEPTION statement, the error code passes back to the caller (the routine, application, or interactive user), and execution aborts. The following example uses two ON EXCEPTION statements with the same error number so that error code 691 can be trapped in two levels of nesting:
Using the IN Clause to Trap Specific ExceptionsA trap is triggered if either the SQL error code or the ISAM error code matches an exception code in the list of error numbers. The search through the list begins from the left and stops with the first match.You can use a combination of an ON EXCEPTION statement without an IN clause and one or more ON EXCEPTION statements with an IN clause to set up default trapping. A summary of the sequence of statements in the following example would be: "Test for an error. If error -210, -211, or -212 occurs, take action A. If error -300 occurs, take action B. If any other error occurs, take action C." When an error occurs, the database server searches for the last declaration of the ON EXCEPTION statement that traps the particular error code.
Receiving Error Information in the SET ClauseIf you use the SET clause, when an exception occurs, the SQL error code and (optionally) the ISAM error code are inserted into the variables that are specified in the SET clause. If you provided an error data variable, any error text that the database server returns is put into the error data variable. Error text includes information such as the offending table or column name.
Errors Within the ON EXCEPTION Statement BlockTo prevent an infinite loop, if an error occurs during execution of the statement block of an error trap, the search for another trap does not include the current trap.
UsageUse the RAISE EXCEPTION statement to simulate an error. An ON EXCEPTION statement can trap the generated error.
If you omit the ISAM error parameter, the database server sets the ISAM error code to zero when the exception is raised. If you want to use the error text variable parameter but not specify a value for ISAM error, you can specify For example, the following statement raises the error number -9999 and returns the stated text: The statement can raise either system-generated exceptions or user-generated exceptions.
In the following example, a negative value for See the ON EXCEPTION statement for more information about the scope and compatibility of exceptions.
UsageThe RETURN statement returns values to the calling module. An SPL routine that returns one or more values is called an SPL function.All the RETURN statements in an SPL function must be consistent with the RETURNING clause of the CREATE FUNCTION statement, which defines the function. The number and data type of values in the RETURN statement, if any, must match in number and data type the data types that are listed in the RETURNING clause of the CREATE FUNCTION statement. You can choose to return no values even if you specify one or more values in the RETURNING clause. If you use a RETURN statement without any expressions, but the calling routine or program expects one or more return values, it is equivalent to returning the expected number of null values to the calling program. In the following example, the SPL function includes two acceptable RETURN statements. A program that calls this function should check if no values are returned and act accordingly. A RETURN statement without any expressions exits only if the SPL function is declared not to return values; otherwise it returns nulls. In an SPL program, you can use an external function as an expression in a RETURN statement provided that the external function is not an iterator function. An iterator function is an external function that returns one or more rows of data and therefore requires a cursor to execute.
![]()
The following example shows a cursor routine that another routine can call. After the RETURN i WITH RESUME statement returns each value to the calling routine or program, the next line of sequence() executes the next time sequence() is called. If backwards equals
SYSTEMUse the SYSTEM statement to make an operating-system command run from within an SPL routine.
UsageIf the supplied expression is not a character expression, expression is converted to a character expression before the operating-system command is made. The complete character expression passes to the operating system and executes as an operating-system command.The operating-system command that the SYSTEM statement specifies cannot run in the background. The database server waits for the operating system to complete execution of the command before it continues to the next statement in the SPL routine. Your SPL routine cannot use a value or values that the command returns. If the operating-system command fails (that is, if the operating system returns a nonzero status for the command), an exception is raised that contains the returned operating-system status as the ISAM error code and an appropriate SQL error code. In routines that contain SYSTEM statements, the operating-system command runs with the permissions of the user who is executing the routine.
For information on the operating-system commands that set environment variables, see Chapter 3 of the Informix Guide to SQL: Syntax.
You can use a double-pipe symbol (||) to concatenate expressions with a SYSTEM statement, as the following example shows:
TRACEUse the TRACE statement to control the generation of debugging output.
UsageThe TRACE statement generates output that is sent to the file that the SET DEBUG FILE TO statement specifies.Tracing prints the current values of the following items: The output of each executed TRACE statement appears on a separate line. If you use the TRACE statement before you specify a DEBUG file to contain the output, an error is generated. Any routine the SPL routine calls inherit the trace state. That is, a called routine assumes the same trace state (ON, OFF, or PROCEDURE) as the calling routine. The called routine can set its own trace state, but that state is not passed back to the calling routine. A routine that is executed on a remote database server does not inherit the trace state.
The TRACE statement does not have ROUTINE or FUNCTION keywords. Therefore, use the TRACE PROCEDURE keywords even if the SPL routine you want to trace is a function.
You can use the TRACE statement with an expression even if you used a TRACE OFF statement earlier in a routine. However, you must first use the SET DEBUG statement to establish a trace-output file. The following example uses a TRACE statement with an expression after it uses a TRACE OFF statement: The following example shows additional TRACE statements:
Looking at the Traced OutputTo see the traced output, use an editor or utility to display or read the contents of the file.
UsageThe condition is evaluated once at the beginning of the loop, and subsequently at the beginning of each iteration. The statement block is executed as long as the condition remains true. The loop terminates when the condition evaluates to not true.If any expression within the condition evaluates to null, the condition automatically becomes not true unless you are explicitly testing for the IS NULL condition. If an expression within the condition has an unknown value because it references uninitialized SPL variables, an immediate error results. In this case, the loop terminates, and an exception is raised.
|
![]() |
![]() |