Undisplayed Graphic

SOLID STORED PROCEDURE GUIDE



INTRODUCTION

Stored procedures are simple programs, or procedures, that are executed in the server. The user can create procedures that contain several SQL statements or whole transactions, and execute them with single call statement. In addition to SQL statements, 3GL type control structures can be used enabling procedural control. In this way complex, data-bound transactions may be run on the server itself, thus rstored procedures reducing network trafficcontrol to access rights and database operations. Granting execute rights on a stored procedure automatically invokes the necessary access rights to all database objects used in the procedure. Therefore, administering database access rights may be greatly simplified by allowing access to critical data through procedures.

This guide explains in detail how to use the SOLID Server stored procedures. In the beginning of this guide the general concepts of using the procedures are explained. Later chapters go further in the actual syntax of different statements in the procedures. In the end of the guide there are sections discussing transaction management, sequences and other advanced stored procedure features.

Basic Procedure Structure

A stored procedure is a standard SOLID database object that can be manipulated using standard DDL statements CREATE and DROP.

In its simplest form a stored procedure definition looks like:

Note: As the SQL Editor is not able to parse these statements the whole statement has to be enclosed in double quotes.

The following example creates a procedure called TEST:

Procedures can be run by issuing a CALL statement followed by the name of the procedure to be invoked:

Naming Procedures

Procedure names have to be unique within a database schema.

All the standard naming restrictions considering database objects, like using reserved words, identifier lengths etc., apply to stored procedure names. See appendix F in the Administrator’s Guide for an overview of reserved words.

Parameter Section

A stored procedure communicate with the calling program using parameters. Stored procedures accept two types of parameters:have three kinds of parameres:

• Input parameters; given as an input to the procedure can be used inside the procedure.

• Output parameters; returned values from the procedure. Stored procedures may return a result set of several rows with output parameters as the columns.

The types temporary storage of column and control values.of parameters must be declared. See appendix C in the Administrator’s Guide for supported data types. The syntax used in parameter declaration is:

Input parameters are declared between parentheses directly after the procedure name, output parameters are declared in a special RETURNS section of the procedure definition:

There can be any number of input and output parameters. Input parameters have to be supplied in the same order as they are defined when the procedure is called.

Declaring input parameters in the procedure heading make their values accessible inside the procedure by referring to the parameter name.

The output parameters will appear in the returned result set. The parameters will appear as columns in the result set in the same order as they are defined. A procedure may return one or rows. Thus, also select statements can be wrapped into database procedures.

The following statement creates a procedure that has two input parameters and two output parameters:

This procedure should be called using two input parameter of data type VARCHAR. The procedure returns an output table consisting of 2 columns named phone_nr of type NUMERIC and CITY of type VARCHAR.

E.g.

Declare Section

Local variables that are used inside the procedure for temporary storage of column and control values are defined in a separate section of the stored procedure directly following the BEGIN keyword.

The syntax of declaring a variable is:

Note that every declare statement should be ended with a semicolon (;).

The variable name is an alphanumeric string that identifies the variable. The data type of the variable can be any valid SQL data type supported. See appendix C in the Administrator’s Guide for supported data types.

E.g.

Note that input and output parameters are treated like local variables within a procedure within the exception that input parameters have a preset value and output parameter values are returned or can be appended to the returned result set.

Procedure Body

The procedure body contains the actual stored procedure program based on assignments, expressions, SQL statements and the likes.

Any type of expression including scalar functions can be used in a procedure body. See appendix D in the Administrator’s Guide for valid expressions.

Assignments

To assign values to variables either of the following syntax is used:

or

Example:

Variables and constants are initialized every time a procedure is executed. By default, variables are initialized to NULL. Unless a variable has been explicitly initialized, its value is undefined, as the following example shows:

Therefore, a variable should never be referenced before it has been assigned a value.

The expression following the assignment operator can be arbitrarily complex, but it must yield a data type that is the same as or convertible to the data type of the variable.

When possible , SOLID procedure language can provide conversion of data types implicitly. This makes it possible to use literals, variables and parameters of one type where another type is expected.

Implicit conversion is not possible if:

• information would be lost in the conversion.

• a string to be converted to an integer contains non-numeric data

Examples:

results in value ‘The value is 1800’ in variable string_var.

results in value ‘123’ in variable string_var.

returns an error.

Expressions

Comparison Operators

Comparison operators compare one expression to another. The result is always TRUE, FALSE, or NULL. Typically, comparisons are used in conditional control statements and allow comparisons of arbitrarily complex expressions. The following table gives the meaning of each operator:

Operator Meaning
= is equal to
<> is not equal to
< is less than
> is greater than
<= is less than or equal to
>= is greater than or equal to

Note that the != notation cannot be used inside a stored procedure, use the ANSI-SQL compliant <> instead.

Logical Operators

The logical operators can be used to build more complex queries. The logical operators AND, OR, and NOT operate according to the tri-state logic illustrated by the truth tables shown below. AND and OR are binary operators; NOT is a unary operator.

NOT true false null
  false true null
AND true false null
true true false null
false false false false
null null false null
OR true false null
true true true true
false true false null
null true null null

As the truth tables show, AND returns the value TRUE only if both its operands are true. On the other hand, OR returns the value TRUE if either of its operands is true. NOT returns the opposite value (logical negation) of its operand. For example, NOT TRUE returns FALSE.

NOT NULL returns NULL because nulls are indeterminate.

When not using parentheses to specify the order of evaluation, operator precedence determines the order.

Note that ‘true’ and ‘false’ are not literals accepted by SQL parser but values. Logical expression value can be interpreted as a numeric variable:

false = 0 or NULL
true = 1 or any other numeric value

Example:

can be simply written

IS NULL Operator

The IS NULL operator returns the Boolean value TRUE if its operand is null, or FALSE if it is not null. Comparisons involving nulls always yield NULL. To test whether a value is NULL, do not use the expression,

because it never evaluates to TRUE.

Instead, use the following statement:

Note that when using multiple logical operators in Solid stored procedures the individual logical expressions should be enclosed in parentheses like:

Control Structures

IF Statement

Often, it is necessary to take alternative actions depending on circumstances. The IF statement executes a sequence of statements conditionally. There are three forms of IF statements: IF-THEN, IF-THEN-ELSE, and IF-THEN-ELSEIF.

IF-THEN

The simplest form of IF statement associates a condition with a statement list enclosed by the keywords THEN and END IF (not ENDIF), as follows:

The sequence of statements is executed only if the condition evaluates to TRUE. If the condition evaluates to FALSE or NULL, the IF statement does nothing. In either case, control passes to the next statement. An example follows:

IF-THEN-ELSE

The second form of IF statement adds the keyword ELSE followed by an alternative statement list, as follows:

The statement list in the ELSE clause is executed only if the condition evaluates to FALSE or NULL. Thus, the ELSE clause ensures that a statement list is executed. In the following example, the first or second assignment statement is executed when the condition is true or false, respectively:

THEN and ELSE clauses can include IF statements. That is, IF statements can be nested, as the following example shows:

IF-THEN-ELSEIF

Occasionally it is necessary to select an action from several mutually exclusive alternatives. The third form of IF statement uses the keyword ELSEIF to introduce additional conditions, as follows:

If the first condition evaluates to FALSE or NULL, the ELSEIF clause tests another condition. An IF statement can have any number of ELSEIF clauses; the final ELSE clause is optional. Conditions are evaluated one by one from top to bottom. If any condition evaluates to TRUE, its associated statement list is executed and the rest of the statements (inside the IF-THEN-ELSEIF) are skipped. If all conditions evaluate to FALSE or NULL, the sequence in the ELSE clause is executed. Consider the following example:

If the value of "sales" is more than 50000, the first and second conditions are true. Nevertheless, "bonus" is assigned the proper value of 1500 since the second condition is never tested. When the first condition evaluates to TRUE, its associated statement is executed and control passes to the next statement following the IF-THEN-ELSEIF.

When possible, use the ELSEIF clause instead of nested IF statements. That way, the code will be easier to read and understand. Compare the following IF statements:

  • IF <condition1> THEN
  • IF <condition1> THEN 
  •   <statement-list1>;
  •   <statement-list1>; 
  • ELSE
  • ELSEIF <condition2> THEN 
  •   IF <condition2> THEN
  •   <statement-list2>; 
  •     <statement-list2>;
  • ELSEIF <condition3> THEN 
  •   ELSE
  •   <statement-list3>; 
  •     IF <condition3> THEN
  • END IF
  •       <statement-list3>;

  •     END IF

  •   END IF

  • END IF

These statements are logically equivalent, but the first statement obscures the flow of logic, whereas the second statement reveals it.

WHILE-LOOP

The WHILE-LOOP statement associates a condition with a sequence of statements enclosed by the keywords LOOP and END LOOP, as follows:

Before each iteration of the loop, the condition is evaluated. If the condition evaluates to TRUE, the statement list is executed, then control resumes at the top of the loop. If the condition evaluates to FALSE or NULL, the loop is bypassed and control passes to the next statement. An example follows:

The number of iterations depends on the condition and is unknown until the loop completes. Since the condition is tested at the top of the loop, the sequence might execute zero times. In the latter example, if the initial value of "total" is greater than 25000, the condition evaluates to FALSE and the loop is bypassed, altogether

Loops can be nested. When an inner loop is finished control is returned to the next loop. The procedure continues from the next statement after end loop.

Leaving Loops

It may be necessary to force the procedure to leave a loop prematurely. This can be implemented using the LEAVE keyword:

Upon successful evaluation of the <exit_condition> the loop is left, and the procedure continues at the statement list 2.

Note that although SOLID Server supports from version 2.2 onwards the ANSI-SQL CASE syntax, the CASE construct cannot be used inside a stored procedure as a control structure!

Handling Nulls

Nulls can cause confusing behaviour. Some common mistakes can be avoided by keeping the following rules in mind:

• comparisons involving nulls always yield NULL

• applying the logical operator NOT to a null yields NULL

• in conditional control statements, if the condition evaluates to NULL, its associated sequence of statements is not executed

In the example below, you might expect the statement list to execute because "x" and "y" seem unequal. Remember though that nulls are indeterminate. Whether "x" is equal to "y" or not is unknown. Therefore, the IF condition evaluates to NULL and the statement list is bypassed.

In the next example, one might expect the statement list to execute because "a" and "b" seem equal. But, again, this is unknown, so the IF condition evaluates to NULL and the statement list is bypassed.

NOT Operator

Applying the logical operator NOT to a null yields NULL. Thus, the following two statements are not always equivalent:

  •    IF  x > y THEN       
  •      IF NOT x > y THEN 
  •      high := x;      
  •          high := y; 
  •    ELSE                
  •      ELSE 
  •      high := y;      
  •          high := x; 
  •    END IF            
  •      END IF

The sequence of statements in the ELSE clause is executed when the IF condition evaluates to FALSE or NULL. If either or both "x" and "y" are NULL, the first IF statement assigns the value of "y" to "high", but the second IF statement assigns the value of "x" to "high". If neither "x" nor y" is NULL, both IF statements assign the corresponding value to "high".

Zero-Length Strings

Zero length strings are treated by SOLID Server like they are : a string of zero length, instead of like a null. NULL values should be specifically assigned like in the following:

This also means that checking for NULL values will return FALSE when applied to a zero-length string.

Example

Following is an example of a simple procedure that determines whether a person is and adult on the basis of a birthday as input parameter.

Note the usage of {} on scalar functions, and semicolons to end assignments and IF/END IF structures.

Exiting a Procedure

A procedure may be exited prematurely by issuing the keyword

at any location. After this keyword control is directly handed to the program calling the procedure, returning the values bound to the output parameters as indicated in the returns-section of the procedure definition.

Returning Data

By default a stored procedure returns one row of data. The row is returned when the complete procedure has been run or has been forced to exit. This row conforms to the declared output parameters in the parameter section of the procedure.

Starting from SOLID Server 2.2 it is also possible to return result sets from a procedure using the following syntax:

Every RETURN ROW call adds a new row into the returned result set.

USING SQL IN A STORED PROCEDURE

Using SQL statements inside a stored procedure is somewhat different from issuing SQL directly from tools like SQL Editor.

Any SQL statement will have to be executed through an explicit cursor definition. A cursor is a specific allocated part of the server process memory in which track is kept of the statement being processed. Memory space is allocated for holding one row of the underlying statement, together with some status information on the current row (in SELECTS) or the number of rows affected by the statement (in UPDATES, INSERTS and DELETES).

In this way query results are processed one row at a time. The stored procedure logic should take care of the actual handling of the rows, and the positioning of the cursor on the required row(s).

There are five basic steps in handling a cursor:

1. Preparation of the cursor - the definition

2. Executing the cursor - executing the statement

3. Fetching on the cursor (for select procedure calls) - getting the results row by row

4. Closing the cursor after use - still enabling it to re-execute

5. Dropping the cursor from memory - definitely removing it

1. Preparation of a Cursor

A cursor is defined (prepared) using the following syntax:

By preparing a cursor, memory space is allocated to accommodate one row of the result set of the statement, the statement is parsed and optimized.

A cursor name given for the statement has to be unique within the connection. When a cursor is prepared SOLID Server checks that no other cursor of this name is currently open. If there is one, error number 14504 is returned.

Note that statement cursors can be opened also using the ODBC API. Also these cursor names need to be different from the cursors opened from procedures.

Example:

This statement will prepare the cursor named sel_tables, but will not execute the statement that it contains.statements have to be prepared before they can be executed. The preparation optimizes the statement and opens a cursor the statement. In preparation phase possible parameters for the statement are indicated using the question mark ‘?’ placeholder for a parameter.

The syntax of the preparation is:

A cursor name given for the statement has to be unique in the whole database. When a cursor is prepared SOLID Server checks that no other cursor of this name is currently open. If there is one, error number 14504 is returned.

Note that statement cursors can be opened also using the ODBC API. Also these cursors need to be different from the cursors opened from procedures.

The following example prepares an SQL statement and opens cursor el. is executed.

2. Executing the Cursor

Once a procedure has been successfully prepared it can be executed. An execute binds possible input and output variables to it and runs the actual statement.

Syntax of the execute statement is:

The optional section INTO binds result data of the statement to variables.

Variables listed in parenthesis after the INTO keyword are used when running a SELECT or CALL statement. The resulting columns of the SELECT or CALL statement are bound to these variables when the statement is executed. The variables are bound starting from the left-most column listed in the statement. Binding of variables continues to the following column until all variables in the list of variables have been bound. For example to extend the sequence for the cursor sel_tables that was prepared earlier we need to run the following statements:

The statement is now executed and the resulting table names will be returned into variable tab in the subsequent Fetch statements.

3. Fetching on the Cursor

When a SELECT or CALL statement has been prepared and executed it is ready for fetching data from it. Other statements (UPDATE,INSERT,DELETE, DDL) do not require fetching as there will be no result set. Fetching results is done using the fetch syntax:

This command fetches a single row from the cursor to the variables that were bound with the INTO keyword when the statement was executed.

To complete the previous example to actually get result rows back , the statements will look like:

After this the variable tab will contain the table name of the first table found conforming to the WHERE-clause.

Subsequent calls to fetch on the cursor sel_tables will get the next row(s) if the select found more than one.

To fetch all table names a loop construct may be used:

Note that after the completion of the loop the variable tab will contain the last fetched table name.

4. Closing the Cursor

Cursors may be closed by issuing the statement

This will not remove the actual cursor definition from memory, it may be re-executed when the need arises.

5. Dropping the Cursor

Cursors may be dropped from memory, releasing all resources by the statement :

Error Handling

SQLSUCCESS

The return value of the latest EXEC SQL statement executed inside a procedure body is stored into variable SQLSUCCESS. This variable is automatically generated for every procedure. If the previous SQL statement was successful, the value 1 is stored into SQLSUCCESS. After a failed SQL statement, a value 0 is stored into SQLSUCCESS.

The value of SQLSUCCESS may be used, for instance, to determine when the cursor has reached the end of the result set as in the following example:

SQLROWCOUNT

After the execution of UPDATE, INSERT and DELETE statements an additional variable is available to check the result of the statement. Variable SQLROWCOUNT contains the number of rows affected by the last statement.

SQLERROR OF Cursorname

For error checking of EXEC SQL statements the SQLSUCCESS variable may be used like indicated above. To return the actual error that caused the statement to fail to the calling application the following syntax may be used:

Processing will stop immediately when this statement is executed and the procedure return code is SQL_ERROR. The actual database error can be returned using SQLError function:

From SOLID Server 2.2 onwards the need to code

after every SQL statement in a procedure can be diminished by using the following syntax:

When this statement is included in a stored procedure all return values of executed SQL statements are checked for errors. If statement execution returns an error, the procedure is automatically aborted and SQLERROR of the last cursor is returned. Optionally the transaction can be rolled back.

The statement should be included before any EXEC SQL statements directly following the DECLARE section of variables.

Procedure Example

Below is an example of a complete procedure returning all table names from SYS_TABLES that start with ‘SYS’:

Parameter Markers in Cursors

In order to make a cursor more dynamic, an SQL statement can contain parameter markers that indicate values that are bound to the actual parameter values at execute time. As parameter marker the ? symbol is used.

Syntax example:

The execution statement is adapted by including a USING keyword to accommodate the binding of a variable to the parameter marker.

In this way a single cursor can be used multiple times without having to re-prepare the cursor. As preparing a cursor involves also the parsing and optimizing of the statement, significant performance gains can be achived by using re-usable cursors.

Note that the USING list only accepts variables, data can not be directly passed in this way. So if e.g. an insert into a table should be made, one column value of which should always be the same ( status = ‘NEW’) then the following syntax would be wrong:

The correct way would be to define the constant value in the prepare section:

Note that variables can be used multiple times in the using list!

The parameters in a SQL statement have no intrinsic data type or explicit declaration. Therefore, parameter markers can be included in an SQL statement only if their data types can be inferred from another operand in the statement.

For example, in an arithmetic expression such as ? + COLUMN1, the data type of the parameter can be inferred from the data type of the named column represented by COLUMN1. A procedure cannot use a parameter marker if the data type cannot be determined.

The following table describes how a data type is determined for several types of parameters.

Location of Parameter Assumed Data Type
One operand of a binary arithmetic or comparison operator Same as the other operand
The first operand in a BETWEEN clause Same as the other operand
The second or third operand in a BETWEEN clause Same as the first operand
An expression used with IN Same as the first value or the result column of the subquery
A value used with IN Same as the expression
A pattern value used with LIKE VARCHAR
An update value used with UPDATE Same as the update column

An application cannot place parameter markers in the following locations:

• As a SQL identifier (name of a table, name of a column etc.)

• In a SELECT list.

• As both expressions in a comparison-predicate.

• As both operands of a binary operator.

• As both the first and second operands of a BETWEEN operation.

• As both the first and third operands of a BETWEEN operation.

• As both the expression and the first value of an IN operation.

• As the operand of a unary + or - operation.

• As the argument of a set-function-reference.

For more information, see the ANSI SQL-92 specification.

In the following example, a stored procedure will read rows from one table and insert parts of them in another, using multiple cursors:

Calling Other Procedures

As calling a procedure forms a part of the supported SQL syntax, a stored procedure may be called from within another stored procedure. Like all SQL statements a cursor should be prepared and executed like:

If procedure my_proc returns one or more values, then subsequently a fetch should be done on the cursor cp to retrieve those values:

Note that if the called procedure uses a return row statement, the calling procedure should utilize a WHILE LOOP construct to fetch all results.

Recursive calls are possible, but discouraged because cursor names are unique at connection level and infinite recursion may crash the server process.

Positioned Updates and Deletes

In SOLID Server procedures it is possible to use positioned updates and deletes. This means that an update or delete will be done to a row where a given cursor is currently positioned. The positioned updates and deletes can also be used within stored procedures using the cursor names used within the procedure.

Following syntax is used for positioned updates

and for deletes

In both cases the <cursor_name>refers to a statement doing a SELECT on the table that is to be updated/deleted from.

Positioned cursor update is a semantically suspicious concept in SQL standard that may cause peculiarities also with SOLID Server. Please note the following restriction when using positioned updates.

Below is an example written with pseudo code that will cause an endless loop with SOLID Server (error handling, binding variables & other important tasks omitted for brevity and clarity):

The endless loop is caused by the fact that when the update is committed, a new version of the row becomes visible in the cursor and it is accessed in the next FETCH statement. This happens because the incremented row version number is included in the key value and the cursor finds the changed row as the next greater key value after the current position. The row gets updated again, the key value is changed and again it will be the next row found.

In the above example, the updated column2 is not assumed to be part of the primary key for the table, and the row version number was the only index entry changed. However, if such a column value is changed that is part of the index through which the cursor has searched the data, the changed row may jump further forward or backward in the search set.

For these reasons, using positioned update is not recommended in general and searched update should be used instead whenever possible. However, sometimes the update logic may be too complex to be expressed in SQL WHERE clause and in such cases positioned update can be used as follows:

Positioned cursor update works deterministically in SOLID, when the where clause is such that the updated row does not match the criteria and therefore does not reappear in the fetch loop. Constructing such a search criteria may require using additional column only for this purpose.

Note that other users' changes do not become visible in the open cursor, only those committed within the same database session.

Transactions

Stored procedures use transactions like any other interface to the database. A transaction may be committed or rolled back either inside the procedure or outside the procedure. Inside the procedure a commit or roll back is done using the following syntax:

These statements end the previous transaction and start a new one.

If a transaction is not committed inside the procedure, it may be ended externally using:

• the SQL API,

• another stored procedure or

• by autocommit, if the connection has AUTOCOMMIT switch set to ON.

Note that when a connection has autocommit activated it does not force autocommit inside a procedure. The commit is done when the procedure exits.

Default Cursor Management

By default, when a procedure exits, all cursors opened in a procedure are closed. Closing cursors means that cursors are left in prepared state and can be re-executed.

After exit the procedure is put on the procedure cache. When the procedure is dropped from the cache, all cursors are finally dropped.

The number of procedures kept in cache is determined by the solid.ini file setting :

This means that, as long as the procedure is on the procedure cache, all cursors can be re-used as long as they are not dropped. SOLID Server itself manages this by keeping track of the cursors declared, and notices if the statement a cursor contains has been prepared.

As cursor management, especially in a heavy multi-user environment, can use a considerable amount of server resources it is good practice to always close cursors immediately and preferably also drop all cursors that are not used anymore.

Only the most frequently used procedures may be left non-dropped to reduce the cursor preparation effort.

Note that transactions are not related to procedures or other statements. Commit or rollback does therefore NOT release any resources in a procedure.

Notes on SQL

• There is no restriction on the SQL statements used. Any valid SQL statement can be used inside a stored procedure, including DDL and DML statements

• Cursors may be declared anywhere in a stored procedure. Cursors that are certainly going to be used are best prepared directly following the declare section.

• Cursors that are used inside control structures, and are therefore not always necessary, are best declared at the point where they are activated, to limit the amount of open cursors and hence the memory usage.

• The cursor name is an undeclared identifier, not a variable; it is used only to reference the query. You cannot assign values to a cursor name or use it in an expression.

• Cursors may be re-executed repeatedly without having to re-prepare them. Note that this can have a serious influence on performance; repetitively preparing cursors on similar statements may decrease the performance by around 40% in comparison to re-executing already prepared cursors!

• Any SQL related statement will have to be preceded by the keywords EXEC SQL.

MISCELLANEOUS

Using Sequences

SOLID sequences can only be accessed through stored procedures. After creation of the sequence by:

the current sequence value can be retrieved by using the following syntax:

New sequence values can be retrieved using the following syntax:

It is also possible to set the current value of a sequence to a predefined value by using the following syntax:

An example of using a stored procedure to retrieve a new sequence number is given below:

Using Events

Event alerts are special objects in a SOLID Server database. They are used for sending events from one application to another. The use of event alerts removes resource consuming database polling from applications.

The system does not automatically generate events, they must be triggered by stored procedures. Similarly the events can only be received in stored procedures. When an application calls a stored procedure that waits for a specific event to happen, the application is blocked until the event is triggered and received. In multithreaded environments separate threads and connections can be used to access the database during the event standstill.

An event has a name that identifies it and a set of parameters. The name can be any user-specified alphanumeric string. An event object is created with the SQL statement

The parameter list specifies parameter names and parameter types. The parameter types are normal SQL types. Events are dropped with the SQL statement

Events are triggered and received inside stored procedures. Special stored procedure statements are used to trigger and receive events.

The event is triggered with the stored procedure statement

Event parameters must be local variables or parameters in the stored procedure where the event is triggered. All clients that are waiting for the posted event will receive the event.

To make a procedure wait for an event to happen, the WAIT EVENT construct is used in the stored procedure:

Procedure Privileges

Stored procedures are owned by the creator, and are part of the creator’s schema. Users needing to run stored procedures in other schema’s need to be granted EXECUTE privilege on the procedure:

All database objects accessed within the granted procedure , even subsequently called procedures, are accessed according the rights of the owner of the procedure. No special grants are necessary.