db2 Dev Routines 115 PDF
db2 Dev Routines 115 PDF
Routines
2020-08-21
IBM
Notices
This information was developed for products and services offered in the US. This material might be
available from IBM in other languages. However, you may be required to own a copy of the product or
product version in that language in order to access it.
IBM may not offer the products, services, or features discussed in this document in other countries.
Consult your local IBM representative for information on the products and services currently available in
your area. Any reference to an IBM product, program, or service is not intended to state or imply that only
that IBM product, program, or service may be used. Any functionally equivalent product, program, or
service that does not infringe any IBM intellectual property right may be used instead. However, it is the
user's responsibility to evaluate and verify the operation of any non-IBM product, program, or service.
IBM may have patents or pending patent applications covering subject matter described in this
document. The furnishing of this document does not grant you any license to these patents. You can send
license inquiries, in writing, to:
For license inquiries regarding double-byte character set (DBCS) information, contact the IBM Intellectual
Property Department in your country or send inquiries, in writing, to:
Each copy or any portion of these sample programs or any derivative work must include a copyright
notice as follows:
© (your company name) (year).
Portions of this code are derived from IBM Corp. Sample Programs.
© Copyright IBM Corp. _enter the year or years_.
Trademarks
IBM, the IBM logo, and ibm.com are trademarks or registered trademarks of International Business
Machines Corp., registered in many jurisdictions worldwide. Other product and service names might be
trademarks of IBM or other companies. A current list of IBM trademarks is available on the web at
"Copyright and trademark information" at www.ibm.com/legal/copytrade.shtml.
Linux is a registered trademark of Linus Torvalds in the United States, other countries, or both.
Microsoft, Windows, Windows NT, and the Windows logo are trademarks of Microsoft Corporation in the
United States, other countries, or both.
UNIX is a registered trademark of The Open Group in the United States and other countries.
Java and all Java-based trademarks and logos are trademarks or registered trademarks of Oracle and/or
its affiliates.
ii Notices
Applicability
These terms and conditions are in addition to any terms of use for the IBM website.
Personal use
You may reproduce these publications for your personal, noncommercial use provided that all proprietary
notices are preserved. You may not distribute, display or make derivative work of these publications, or
any portion thereof, without the express consent of IBM.
Commercial use
You may reproduce, distribute and display these publications solely within your enterprise provided that
all proprietary notices are preserved. You may not make derivative works of these publications, or
reproduce, distribute or display these publications or any portion thereof outside your enterprise, without
the express consent of IBM.
Rights
Except as expressly granted in this permission, no other permissions, licenses or rights are granted, either
express or implied, to the publications or any information, data, software or other intellectual property
contained therein.
IBM reserves the right to withdraw the permissions granted herein whenever, in its discretion, the use of
the publications is detrimental to its interest or, as determined by IBM, the above instructions are not
being properly followed.
You may not download, export or re-export this information except in full compliance with all applicable
laws and regulations, including all United States export laws and regulations.
IBM MAKES NO GUARANTEE ABOUT THE CONTENT OF THESE PUBLICATIONS. THE PUBLICATIONS ARE
PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, NON-
INFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
Notices iii
iv IBM Db2 V11.5: Routines
Contents
Notices...................................................................................................................i
Trademarks...................................................................................................................................................ii
Terms and conditions for product documentation......................................................................................ii
Figures................................................................................................................ vii
Tables.................................................................................................................. ix
Index................................................................................................................ 223
v
vi
Figures
1. Classifications of routines............................................................................................................................. 4
vii
viii
Tables
8. Parameter styles......................................................................................................................................... 65
13. Mapping of SQL and OLE data types to BASIC and C++ data types...................................................... 199
14. Mapping of the database data types to the OLE DB data types............................................................ 204
ix
x
Chapter 1. Developing Routines
Development of routines is often done when there is no built-in routine available that provides the
functionality that is required.
There are different functional types of routines and routine implementations, however the basic steps for
developing routines are common for all routines. You must determine what type of routine to create, what
implementation to use, define the interface for the routine, develop the routine logic, execute SQL to
create the routine, test your routine, and then deploy it for general use.
The following procedure provides steps for getting started with the routine development.
Procedure
1. Determine whether an existing built-in routine already meets your routine needs.
• If a built-in routine meets your needs, you might want to refer to “Invoking routines” on page 205.
2. Determine what functional type of routine to develop.
3. Determine what routine implementation to use.
• If a SQL routine is required, refer to the information about SQL routines (SQL PL).
• If an external routine is required, refer to the information about “External routines” on page 54.
What to do next
The development of SQL and external routines is similar, but there are differences. For both types of
routines, you must first design your logic, and then to create the routine in the database but the CREATE
statement is specific to the routine type. These routine creation statements include CREATE PROCEDURE,
CREATE FUNCTION, and CREATE METHOD. The clauses specific to each of the CREATE statements define
characteristics of the routine, including the routine name, the number and type of routine parameters,
and details about the routine logic. The database manager uses the information that is provided by the
clauses to identify and run the routine when it is called. Upon successful execution of the CREATE
statement for a routine, the routine is created in the database. The characteristics of the routine are
stored in the database system catalog tables that users can query. Executing the CREATE statement to
create a routine is also referred to as defining a routine or registering a routine.
Because external routines have their logic implemented in user-created libraries or classes that are
located in the database file system, additional steps are required to program the logic, build it, and
properly locate the resulting library or class file.
Once you have developed routines, you can perform the following steps:
Routines
Routines are database objects that can encapsulate programming and database logic that can be invoked
like a programming sub-routine from a variety of SQL interfaces.
Routines can be built in, which means that they are provided with the product, or user-defined, which
means that users can create them. Routines can be implemented using SQL statements, a programming
language, or a mix of both. Different types of routines provide different interfaces that can be used to
extend the functionality of SQL statements, client applications, and some database objects.
For a complete view of the types of routines and implementations that are supported by the database
manager, refer to the topic: “Types of routines” on page 3.
Overview of routines
Routines are a type of database object that you can use to encapsulate logic that can be invoked like a
programming subroutine. There are many useful applications of routines within a database or database
application architecture. You can use routines to improve overall database design, database performance,
and data security, as well as to implement basic auditing mechanisms, and more.
Types of routines
There are many different types of routines. Routines can be grouped in different ways, but are primarily
grouped by their system or user definitions, by their functionality, and by their implementation.
The supported routine definitions are:
• “Built-in routines” on page 5
• “User-defined routines” on page 5
The supported functional types of routines are:
• “Routines: Procedures” on page 8 (also called stored procedures)
• “Routines: Functions” on page 9
• “Routines: Methods” on page 13
The supported routine implementations are:
• “Built-in routine implementation” on page 18
• “Sourced routine implementation” on page 18
• “SQL routine implementation” on page 18
• “External routine implementation” on page 18
The following diagram illustrates the classification hierarchy of routines. All routines can be either built-in
or user-defined. The functional types of routines are in dark grey/blue boxes and the supported routine
implementations are in light grey/orange boxes. Built-in routine implementations are emphasized,
because this type of implementation is unique.
Built-in routines
Built-in routines are routines that are provided with the product. These routines provide a wide variety of
routine support for tasks ranging from administrative functions to database system and catalog reporting.
They are characterized by the fact that they are immediately ready-to-use, require no prerequisite setup
or routine registration steps, although users require privileges to invoke these routines. These can include
built-in routines and are also called SQL Administrative Routines.
Built-in routines provide standard operator support and basic scalar function and aggregate function
support. Built-in routines are the first choice of routine that you should use because they are strongly
typed and will provide the best performance. Do not create external routines that duplicate the behavior
of built-in routines. External routines cannot perform as well as, or be as secure as, built-in routines.
Other built-in routines that you can use are provided with the database in the SYSPROC, SYSFUN, and
SYSTOOLS schemas. These routines are essentially SQL and external routines that are defined by the
system and provided with the product. Although these additional routines are shipped with the database,
they are not built-in routines. Instead they are implemented as pre-installed user-defined routines. These
routines typically encapsulate a utility function such as the REBIND_ROUTINE_PACKAGE procedure. You
can immediately use these functions and procedures, provided that you have the SYSPROC schema and
SYSFUN schema in your CURRENT PATH special register. You can peruse the set of built-in routines if you
are considering implementing an external routine that performs administrative functions.
Of particular interest, you might find the ADMIN_CMD procedure useful as it provides a standard interface
for executing many popular database commands through an SQL interface.
Built-in routines make it faster and easier for you to implement complex SQL queries and powerful
database applications because they are ready-to-use.
User-defined routines
You can create routines to encapsulate logic of your own or use the database provide routines that
capture the functionality of most commonly used arithmetic, string, and casting functions. The user-
defined routines refer to any procedures, functions, and methods that are created by the user.
You can create your own procedures, functions and methods in any of the supported implementation
styles for the routine type. Generally the prefix 'user-defined' is not used when referring to procedures
and methods. User-defined functions are also commonly called UDFs.
Whenever it is possible to do so, you should choose to use the built-in routines. These are provided to
facilitate SQL statement formulation and application development and are optimized to perform well.
User-defined routines give you the flexibility to build your own routines where no built-in routine performs
the specific business logic that you want to implement.
Procedure
To determine whether to use a built-in or user-defined routine:
1. Determine what functionality you want the routine to encapsulate.
2. Check the list of available built-in routines to see if there are any that meet some or all of your
requirements.
• If there is a built-in routine that meets some, but not all of your requirements:
– Determine if the functionality that is missing, is functionality that you can add simply to your
application? If so, use the built-in routine and modify your application to cover the missing
functionality. If the missing functionality is not easily added to your application or if the missing
functionality would have to be repeated in many places consider creating a user-defined routine
that contains the missing functionality and that invokes the built-in routine.
Results
To save time and effort, whenever possible consider using built-in routines. There will be times when the
functionality that you require will not be available within a built-in routine. For these cases you must
create a user-defined routine. Other times it might be possible to include a call to built-in routine from a
user-defined routine that covers the extra functionality that you require.
Routines: Procedures
Procedures, also called stored procedures, are database objects created by executing the CREATE
PROCEDURE statement. Procedures can encapsulate logic and SQL statement and can serve as sub-
routine extensions to client applications, routines, triggers, and dynamic compound statements.
Procedures are invoked by executing the CALL statement with a reference to a procedure. Procedures can
take input, output, and input-output parameters, execute a wide variety of SQL statements, and return
multiple result sets to the caller.
Features
• Enable the encapsulation of logic elements and SQL statements that formulate a particular
subroutine module
• Can be called from client applications, other routines, triggers, and dynamic compound statements -
from anywhere that the CALL statement can be executed.
• Return multiple result-sets
• Support the execution of a large set of SQL statements including SQL statements that read or
modify table data in both single and multiple partition databases
• Parameter support for input, output, and input-output parameters
• Nested procedure calls and function invocations are supported
Routines: Functions
Functions are relationships between sets of input data values and a set of result values. They enable you
to extend and customize SQL. Functions are invoked from within elements of SQL statements such as a
select-list or a FROM clause.
There are four types of functions:
• Aggregate functions
• Scalar functions
• Row functions
• Table functions
Aggregate functions
Also called a column function, this type of function returns a scalar value that is the result of an
evaluation over a set of like input values. The similar input values can, for example, be specified by a
column within a table, or by tuples in a VALUES clause. This set of values is called the argument set.
Scalar functions
A scalar function is a function that, for each set of one or more scalar parameters, returns a single
scalar value. Examples of scalar functions include the LENGTH function, and the SUBSTR function.
Scalar functions can also be created that do complex mathematical calculations on function input
parameters. Scalar functions can be referenced anywhere that an expression is valid within an SQL
statement, such as in a select-list, or in a FROM clause. The following example shows a query that
references the built-in LENGTH scalar function:
Row functions
A row function is a function that for each set of one or more scalar parameters returns a single row.
Row functions can only be used as a transform function mapping attributes of a structured type into
built-in data type values in a row.
Table functions
Table functions are functions that for a group of sets of one or more parameters, return a table to the
SQL statement that references it. Table functions can only be referenced in the FROM clause of a
SELECT statement. The table that is returned by a table function can participate in joins, grouping
operations, set operations such as UNION, and any operation that could be applied to a read-only
view. The following example demonstrates an SQL table function that updates an inventory table and
returns the result set of a query on the updated inventory table:
UPDATE Inventory as I
SET quantity = quantity + amount
WHERE I.itemID = itemNo;
RETURN
SELECT I.itemName, I.quantity
FROM Inventory as I
WHERE I.itemID = itemNo;
END
Interoperability • Procedures can call • Functions can contain • Methods can invoke
other procedures and SQL statements that functions with an SQL
can contain SQL invoke other functions access level less than or
statements that invoke and can call procedures equal to the SQL access
functions with SQL with SQL access levels level of the method.
access levels less than less than or equal to the • Methods cannot call
or equal to the SQL SQL access level of the procedures or other
access level of the function. methods
procedure.
In general the functional characteristics and applications of routines determine what routine type should
be used. However, performance and the supported routine implementations also play an important role in
determining what routine type should be used.
Determining what routine type is best suited to your needs before beginning to implement it will save you
time and possible frustration later.
Read about the functional types of routines to learn about their characteristics.
Procedure
To determine whether to use a procedure, function, or method, do the following:
1. Determine what functionality you want the routine to encapsulate, what interface you want to invoke
the routine from, and what routine implementation you want to use.
• See the following topic:
– “Comparison of functional types of routines” on page 13
to determine what functional routine types support these requirements.
Results
In general functional and SQL requirements motivate the choice of what functional type of routine to
implement. However, there are cases where it is possible to create logically equivalent routines with
different functional types. For example, it is possible to rewrite most basic procedures that return a single
result-set as a table function. You can also easily rewrite basic procedures with only a single output
parameter as scalar functions.
What to do next
Once you have determined what functional type of routine to use, you might be interested in learning
more about routine implementations or in determining what routine implementation to use.
Implementations of routines
Routines can be implemented in a variety of ways. A routine implementation is essentially the underlying
form of the routine that contains the logic that is run when a routine is invoked. Understanding the
different supported routine implementations can help you understand how routines work and help you
determine which routine implementation to choose when implementing user-defined routines.
The available routine implementations include:
• “Built-in routine implementation” on page 18
• “Sourced routine implementation” on page 18
• “SQL routine implementation” on page 18
• “External routine implementation” on page 18
“Built-in routines” on page 5 can be implemented as built-in routines, SQL routines, or external routines.
However, their implementation is essentially invisible to the user and in general is of little concern to the
user.
“User-defined routines” on page 5 can be implemented as sourced routines, SQL routines, or external
routines.
The characteristics of each of the implementations differ and can result in more or less functionality
support. Before deciding on a particular implementation, it is a good idea to review the supported
functionality and restrictions associated with each implementation, by reading about each of the
implementations and then by reading the topic:
• “Comparison of routine implementations” on page 25
A good understanding of the routine implementations can help you make good implementation decisions
as well as help you to debug and troubleshoot existing routines.
Comparison of supported APIs and programming languages for external routine development
It is important to consider the characteristics and limitations of the various supported external routine
application programming interfaces (APIs) and programming languages before you start implementing
JDBC (Java) and • High-level • Java routines • Java routines • Good • To avoid
SQLJ (Java) object- do not perform are safer than scalability potentially
oriented as well as C C and C++ • Java routines dangerous
programming and C++ routines, created with operations,
language routines or because the the FENCED Java Native
suitable for SQL routines. control of THREADSAFE Interface (JNI)
developing dangerous clause (the calls from Java
standalone operations is default) scale routines are
applications, handled by the well. All not permitted.
applets, and Java Virtual fenced Java
servlets. Machine routines will
• Java objects (JVM). This share a few
and data types increases JVMs. More
facilitate the reliability and than one JVM
establishment makes it very might be in use
of database difficult for the on the system
connections, code of one if the Java
execution of Java routine to heap of a
SQL harm another particular
statements, routine db2fmp
and running in the process is
manipulation same process. approaching
of data. exhaustion.
Implementation is • Yes • No • No • No
built into the
database manager
code?
Supported • Not applicable • Functions • Procedures • Procedures
functional routine
types that can have – Scalar functions • Functions • Functions
this implementation – Aggregate • Methods • Methods
functions
Supported SQL • Not applicable • Not applicable • Most SQL • Many SQL
statements statements, statements,
including all SQL including a sub-set
PL statements, of SQL PL
can be executed in statements, can
routines. be executed in
• Refer to the topic, routines.
"SQL statements • Refer to the topic,
that can be "SQL statements
executed in that can be
routines". executed in
routines".
Portability • Not applicable • Sourced functions • SQL functions can • External functions
can easily be be easily dropped can be dropped
dropped and and re-created in and re-created in
recreated in other other databases. other databases,
databases. however care
must be taken to
ensure that the
environment is
compatible and
that the required
supported
software is
available.
• Refer to the topic,
"Deploying
external routines".
Interoperability • Not applicable • They can be • SQL routines can • External routines
referenced be referenced in can invoke
wherever built-in many parts of SQL external routines
functions can be statements. A SQL and other SQL
referenced. routine can invoke routines with SQL
Sourced functions other SQL and access levels that
cannot invoke external routines are equal to or
other functions. with SQL access less than the SQL
levels that are access level of the
equal to or less external routine.
than the SQL
access level of the
SQL routine.
In general the functional characteristics and applications of routines determine what routine type should
be used. However, performance and the supported routine implementations also play an important role in
determining what routine type should be used.
Procedure
To determine whether to use a sourced, SQL, or external routine implementation when creating a routine:
1. Determine whether you want to create a procedure, function, or method. This should always be your
first step when developing a routine. Also determine what are the support implementations for that
routine type. See:
• “Comparison of functional types of routines” on page 13
2. Determine what SQL statements you want to include in the routine. The set of SQL statements that you
want to execute in a routine can limit your choice of routine implementation. See:
• “Determining what SQL statements can be executed in routines” on page 39
3. Determine if now or in the future the routine logic must access data, files, or applications that reside
external to the database. The data, files, or applications might reside in the file system of the database
server or in the available network.
• If the routine logic must access entities outside of the database, you must use an external routine
implementation.
4. Determine the number of queries to be included in the routine relative to the quantity of procedural
flow logic.
• If the routine logic contains primarily procedural flow logic and very few queries, create an external
routine.
• If the routine logic contains many queries and a minimal amount of procedural flow logic, create an
SQL routine.
Usage of routines
Routines can be used to solve many common problems faced by database architects, database
administrators, and application developers alike. They can help improve the structure, maintenance, and
performance of your applications.
The following list provides some examples of scenarios in which you might use routines:
• Administering databases with routines
• Extending SQL function support with user-defined functions
• Auditing data changes using routines and other SQL features
Example
Example 1: Auditing accesses of table data using an SQL table function
This function accesses the salary data of all employees in a department specified by input argument
deptno. It also records in an audit table, named audit_table, the user ID that invoked the function,
the name of the table that was read from, a description of what information was accessed, and the
current time. Note that the table function is created with the keywords MODIFIES SQL DATA because
it contains an INSERT statement that modifies SQL data.
A result set is returned with the last name, first name, and new salary for the employee. The invoker
of the function will not know that the audit record was made.
The audit table would include a new record such as the following:
Example 4: Retrieving rows modified within the body of an SQL table function
This function updates the salary of an employee, specified by an employee number EMPNUM, by an
amount specified by amount, and returns the original values of the modified row or rows to the caller.
This example makes use of a SELECT statement that references a data change statement in the FROM
clause. Specifying OLD TABLE within the FROM clause of this statement flags the return of the original
row data from the table employee that was the target of the UPDATE statement. Using FINAL TABLE,
instead of OLD TABLE, would flag the return of the row values subsequent to the update of table
employee.
Note:
1. Compound SQL (compiled) statements can be used as the body of SQL procedures, SQL functions,
triggers, or as stand-alone statements.
2. Compound SQL (inline) statements can be used as the body of SQL functions, SQL methods, triggers,
or as stand-alone statements.
3. Although the NO SQL option implies that no SQL statements can be specified, non-executable
statements are not restricted.
4. Connection management statements are not allowed in any routine execution context.
5. This situation depends on the statement being executed. The statement specified for the EXECUTE
statement must be allowed in the context of the particular SQL access level in effect. For example, if
the SQL access level READS SQL DATA is in effect, the statement cannot be INSERT, UPDATE, or
DELETE.
6. The COMMIT statement and the ROLLBACK statement (without the TO SAVEPOINT clause) can be
used in a stored procedure, but only if the stored procedure is called directly from an application, or
indirectly through nested stored procedure calls from an application. If any trigger, function, method,
or atomic compound statement is in the call chain to the stored procedure, a COMMIT or a
ROLLBACK of a unit of work is not allowed.
7. If the SQL access level READS SQL DATA is in effect, no SQL data change statement can be
embedded in the SELECT INTO statement or in the cursor referenced by the OPEN statement.
8. SQL routines can only issue CREATE and DROP statements statically for indexes, tables, and views.
For other objects, CREATE and DROP statements can be issued dynamically using the following
statements:
• EXECUTE IMMEDIATE
• PREPARE, followed by EXECUTE
9. The DESCRIBE SQL statement has a different syntax than that of the CLP DESCRIBE command.
10. This is only supported for embedded SQL routines.
11. When referenced in an SQL procedure, the statement can only be executed statically.
12. The procedure that is called must have the same or more restrictive level of SQL data access than the
current level in effect. For example, a routine defined as MODIFIES SQL DATA can call a procedure
defined as MODIFIES SQL DATA, READS SQL DATA, CONTAINS SQL, or NO SQL. A routine defined as
CONTAINS SQL can call a procedure defined as CONTAINS SQL or NO SQL. The arguments specified
Errors
Table 5 on page 33 indicates whether the SQL statement specified by the first column is allowed to
execute inside a routine that has the specified SQL data access level. If the statement exceeds the data
access level, an error is returned when the routine is executed.
• If an executable SQL statement is encountered inside a routine defined with the NO SQL data access
level, then SQLSTATE 38001 is returned.
• For other execution contexts, the SQL statements that are unsupported in any context return an
SQLSTATE 38003 error.
• For other SQL statements that are not allowed in a CONTAINS SQL context, SQLSTATE 38004 is
returned.
• In a READS SQL DATA context, SQLSTATE 38002 is returned.
• During creation of an SQL routine, a statement that does not match the SQL data access level returns an
SQLSTATE 42985 error.
Optimal performance of routines is achieved when the most restrictive SQL access clause that is valid is
specified in the routine CREATE statement.
In the CREATE statement for a routine:
• If you explicitly specify READS SQL DATA, no SQL statement in the routine can modify data.
Procedure
To determine what SQL statements can be invoked in a particular routine:
1. Determine the SQL access level of the routine. If it is an existing routine, examine the CREATE
statement that was used to create the routine. The SQL access level clause might be explicitly defined
in the DDL as one of: NO SQL, CONTAINS SQL, READS SQL DATA, or MODIFIES SQL DATA. If no such
clause is explicitly specified, then the default value for the routine is implied.
• For SQL procedures the default is MODIFIES SQL DATA.
• For SQL functions the default is MODIFIES SQL DATA.
• For external procedures the default is MODIFIES SQL DATA.
• For external functions the default is READS SQL DATA.
2. Refer to the table in the topic, "SQL statements that can be executed in routines". Look up the SQL
statement of interest by name.
3. Check if the SQL statement is supported for the specific type of routine and implementation.
4. Verify that the required SQL access level to execute the statement matches the SQL access level of the
routine.
5. Carefully read any usage notes or footnotes to ensure that there are no other restrictions on the SQL
statement execution.
Portability of routines
Routine portability refers to the ease with which a routine can be deployed. Portability comprises such
factors as operating system compatibility, runtime environment compatibility, software compatibility,
invocation interface compatibility as well as other routine implementation factors such as compatibility of
support for the SQL statements executed within a routine.
Routine portability is essential if the environment to which you will deploy a routine is not identical to the
environment in which the routine was developed. In general routines are highly portable between
operating systems and even between the various database products and editions. It is a good idea to
consider the potential portability problems before you begin developing routines so that you minimize the
likelihood of rework later.
The following topics include information related to factors that can limit the portability of routines:
• Supported database product editions
• Supported development and compiler software
• SQL statements that can be executed in routines
• Restrictions on routines
• Deploying routines
Interoperability of routines
The interoperability of routines of different types and with different programming implementations
ensures that routines can be highly re-useable modules throughout the life-span of a database system.
Because code modules are often implemented by different programmers with programming expertise in
different programming languages, and because it is generally desirable to reuse code wherever possible
to save on development time and costs, the routine infrastructure is designed to support a high degree of
routine interoperability.
Interoperability of routines is characterized by the ability to reference and invoke routines of different
types and implementations from other routines seamlessly and without any additional requirements.
Routines are interoperable in the following ways:
• A client application in one programming language can invoke routines that are implemented in a
different programming language.
– For example, C client applications can invoke Java runtime routines.
• A routine can invoke another routine regardless of the routine type or the implementation language of
the routine.
– For example a Java procedure (one type of routine) can invoke an SQL scalar function (another type
of routine with a different implementation language).
• A routine created in a database server on one operating system can be invoked from a database client
running on a different operating system.
There are various kinds of routines that address particular functional needs and various routine
implementations. The choice of routine type and implementation can impact the degree to which the
benefits listed previously are exhibited. In general, routines are a powerful way of encapsulating logic so
that you can extend your SQL and improve the structure, maintenance, and potentially the performance of
your applications.
Routine implementation: built-in or user-defined • For equivalent logic, built-in routines perform the
best, followed by built-in routines, because they
enjoy a closer relationship with the database engine
than do user-defined routines.
• User-defined routines can perform very well if they
are well coded and follow best practices.
External routine implementation programming • See: Comparison of external routine APIs and
language programming languages for a comparison of the
performance features that you should consider
when selecting an external routine implementation.
• Java (JDBC and SQLJ APIs)
– Java routines with very large memory
requirements are best created with the FENCED
NOT THREADSAFE clause specified. Java routines
with average memory requirements can be
specified with the FENCED THREADSAFE clause.
– For fenced threadsafe Java routine invocations,
the database manager attempt to choose a
threaded Java fenced mode process with a Java
heap that is large enough to run the routine.
Failure to isolate large heap consumers in their
own process can result in out-of-Java-heap errors
in multi-threaded Java db2fmp processes.
FENCED THREADSAFE routines, in contrast,
perform better because they can share a small
number of JVMs.
• C and C++
– In general C and C++ routines perform better than
other external routine implementations and as
well as SQL routines.
– For deployment of routines to both 32-bit and 64-
bit database instances, compile C and C++
routines in 32-bit format.
• COBOL
– In general COBOL performance is good, but
COBOL is not a recommended routine
implementation.
Complexity of SQL statements within the routine • It makes good sense to include very complex
queries within your routines so that you capitalize on
the greater memory and performance capabilities of
the database server.
• Do not worry about the SQL statements being overly
complex.
Static or dynamic SQL execution within routines • In general static SQL performs better than dynamic
SQL. In routines there are no additional differences
when you use static or dynamic SQL.
Data types of routine parameters • You can improve the performance of routines by
using VARCHAR parameters instead of CHAR
parameters in the routine definition. Using VARCHAR
data types instead of CHAR data types prevents the
database manager from padding parameters with
spaces before passing the parameter and decreases
the amount of time required to transmit the
parameter across a network.
For example, if your client application passes the
string "A SHORT STRING" to a routine that expects a
CHAR(200) parameter, the database manager has to
pad the parameter with 186 spaces, null-terminate
the string, then send the entire 200 character string
and null-terminator across the network to the
routine.
In comparison, passing the same string, "A SHORT
STRING", to a routine that expects a VARCHAR(200)
parameter results in the database manager simply
passing the 14 character string and a null terminator
across the network.
Number of local variables in routines • Minimizing the number of local variables declared
within a routine can improve performance by
minimizing the number of SQL statements executed
within the routine.
• In general aim to use as few variables as possible.
Re-use variables if this will not be semantically
confusing.
Number of result sets returned by procedures • If you can reduce the number of result sets returned
by a routine you can improve routine performance.
Size of result sets returned by routines • Make sure that for each result set returned by a
routine, the query defining the result filters the
columns returned and the number of rows returned
as much as possible. Returning unnecessary
columns or rows of data is not efficient and can
result in sub-optimal routine performance.
Level of SQL access in routine: NO SQL, CONTAINS • Routines that are created with a lower level of SQL
SQL, READS SQL DATA, MODIFIES SQL DATA access clause will perform better than routines
created with a higher level of SQL access clause.
Therefore you should declare your routines with the
most restrictive level of SQL access clause. For
example, if your routine only reads SQL data, do not
create it with the MODIFIES SQL DATA clause, but
rather create it with the more restrictive READS SQL
DATA clause.
Determinism of routine (DETERMINISTIC or NOT • Declaring a routine with the DETERMINISTIC or NOT
DETERMINISTIC clause specification) DETERMINISTIC clause has no impact on routine
performance.
Number and complexity of external actions made by • Depending on the number of external actions and
routine (EXTERNAL ACTION clause specification) the complexity of external actions performed by an
external routine, routine performance can be
hindered. Factors that contribute to this are network
traffic, access to files for writing or reading, the time
required to execute the external action, and the risk
associated with hangs in external action code or
behaviors.
Routine invocation when input parameters are null • If receiving null input parameter values results in no
(CALLED ON NULL INPUT clause specification) logic being executed and an immediate return by the
routine, you can modify your routine so that it is not
fully invoked when null input parameter values are
detected. To create a routine that ends invocation
early if routine input parameters are received, create
the routine and specify the CALLED ON NULL INPUT
clause.
Once routines are created and deployed, it might be harder to determine what environmental and routine
specific factors are impacting routine performance, and hence it is important to design routines with
performance in mind.
Security of routines
The security of routines is paramount to ensure their continued functioning, to minimize the risk of
tampering, and to protect the database system environment. There are a few categories of routine
security considerations each with varying levels of risk. One must be aware of these risks when
developing or maintaining routines so as to mitigate unfortunate outcomes as much as possible.
Securing routines
When creating routines it is important to ensure that the routines, routine libraries (in the case of external
routines), and the privileges of the users that will interact with the routines are managed with routine
security in mind.
Whether you are creating a routine, or assessing an existing routine, the procedure for securing a routine
is similar.
1. Definer performs the appropriate CREATE statement to register the routine. This registers the routine
in the database with its intended level of SQL access, establishes the routine signature, and also points
to the routine executable. The definer, if not also the package owner, needs to communicate with the
package owners and authors of the routine programs to be clear on where the routine libraries reside
so that this can be correctly specified in the EXTERNAL clause of the CREATE statement. By virtue of a
successful CREATE statement, the definer has EXECUTE WITH GRANT privilege on the routine,
however the definer does not yet have EXECUTE privilege on the packages of the routine.
2. Definer must grant EXECUTE privilege on the routine to any users who are to be permitted use of the
routine. (If the package for this routine will recursively call this routine, then this step must be done
before the next step.)
3. Package owners precompile and bind the routine program, or have it done on their behalf. Upon a
successful precompile and bind, the package owner is implicitly granted EXECUTE WITH GRANT
OPTION privilege on the respective package. This step follows step one in this list only to cover the
possibility of SQL recursion in the routine. If such recursion does not exist in any particular case, the
precompile/bind could precede the issuing of the CREATE statement for the routine.
4. Each package owner must explicitly grant EXECUTE privilege on their respective routine package to
the definer of the routine. This step must come at some time after the previous step. If the package
owner is also the routine definer, this step can be skipped.
This will result in a conflict because rule 3 is violated. This form of conflict can only be resolved by
redesigning the application or UDF.
The following does not result in a conflict:
Suppose an application issues the statements:
With the cursor, UDF2 is allowed to read table T2 because two table access contexts can read the same
table. The application is allowed to update T2 even though UDF2 is reading the table because UDF2 was
invoked in a different application level statement than the update.
External routines
External routines are routines that have their logic implemented in a programming language application
that resides outside of the database, in the file system of the database server.
The association of the routine with the external code application is asserted by the specification of the
EXTERNAL clause in the CREATE statement of the routine.
You can create external procedures, external functions, and external methods. Although they are all
implemented in external programming languages, each routine functional type has different features.
Before deciding to implement an external routine, it is important that you first understand what external
In this case, the optimizer would open a scan of table_func_1 for each row of table_1. This is because the
value of table_1's col1, which is passed to table_func_1, is used to define the table function scan.
For NO FINAL CALL table UDFs, the OPEN, FETCH, FETCH, ..., CLOSE sequence of calls repeats for each
row of table_1. Note that each OPEN call will get a clean scratchpad. Because the table function does not
know at the end of each scan whether there will be more scans, it must clean up completely during CLOSE
Once the function is defined, you can access the function output using an SQL select statement, which
includes a typed correlation clause. In the following example, the SELECT statement is used to indicate
that the table contains two columns: USER, which is an INTEGER data type, and LINK, which is a
VARCHAR(100) data type.
Select TX.*
From TABLE (csvRead('/TMP/data/userWebClicks.log'))
AS TX (USER INTEGER, LINK VARCHAR(100))
WHERE TX.LINK LIKE 'www.ibm.com%'
You can use another SELECT statement to access the output from the same generic table function. In the
following example, the SELECT statement is used to indicate that this time the table contains three
different columns: CUSTOMERID, which is an INTEGER data type; NAME, which is a VARCHAR(100) data
type; and ADDRESS, which is a VARCHAR(100) data type.
Select TX.*
From TABLE (csvRead('/TMP/data/customerWebClicks.log'))
AS TX (CUSTOMERID INTEGER, NAME VARCHAR(100), ADDRESS VARCHAR(100))'
What to do next
You can now use the new Java function to analyze your data. For example, issue the following SELECT
command:
At each OPEN of the table function • Class constructor is called • UDF method is opened with OPEN
(means new scratchpad). UDF call.
method is called with OPEN call. • Method opens the scan for
• Constructor initializes class and whatever Web data it wants.
scratchpad variables. Method (Might be able to avoid reopen
connect to Web server, and opens after a CLOSE reposition,
the scan for Web data. depending on what is saved in the
scratchpad.)
At each CLOSE of the table function • UDF method is called with CLOSE • UDF method is called with CLOSE
call. close() method if it exists call.
for class. • Method might reposition to the
• Method closes its Web scan and top of the scan, or close the scan.
disconnects from the Web server. It can save any state in the
close() does not need to do scratchpad, which will persist.
anything.
After the last CLOSE of the table • No calls. • UDF method is called with FINAL
function call. close() method is called if
it exists for class.
• Method disconnects from the
Web server. close() method
does not need to do anything.
Note:
1. The term "UDF method" refers to the Java class method that implements the UDF. This is the method
identified in the EXTERNAL NAME clause of the CREATE FUNCTION statement.
The function needs a place to store the current value for the counter between invocations, where the
value will be guaranteed to be the same for the following invocation. On each invocation, the value can
then be incremented and returned as the result of the function.
This type of routine is NOT DETERMINISTIC. Its output does not depend solely on the values of its SQL
arguments.
2. Functions or methods where the performance can be improved by the ability to perform some
initialization actions.
An example of such a function or method, which might be a part of a document application, is a match
function, which returns 'Y' if a given document contains a given string, and 'N' otherwise:
The SCRATCHPAD keyword tells the database manager to allocate and maintain a scratchpad for a
routine. The default size for a scratchpad is 100 bytes, but you can determine the size (in bytes) for a
scratchpad. The match example is 10000 bytes long. The database manager initializes the scratchpad to
binary zeros before the first invocation. If the scratchpad is being defined for a table function, and if the
table function is also defined with NO FINAL CALL (the default), the database manager refreshes the
scratchpad before each OPEN call. If you specify the table function option FINAL CALL, the database
manager does not examine or change the content of the scratchpad after its initialization. For scalar
functions defined with scratchpads, the database manager also does not examine or change the
scratchpad's content after its initialization. A pointer to the scratchpad is passed to the routine on each
invocation, and the database manager preserves the routine's state information in the scratchpad.
So for the counter example, the last value returned could be kept in the scratchpad. And the match
example could keep the list of documents in the scratchpad if the scratchpad is big enough, otherwise it
could allocate memory for the list and keep the address of the acquired memory in the scratchpad.
Scratchpads can be variable length: the length is defined in the CREATE statement for the routine.
The scratchpad only applies to the individual reference to the routine in the statement. If there are
multiple references to a routine in a statement, each reference has its own scratchpad, thus scratchpads
cannot be used to communicate between references. The scratchpad only applies to a single database
agent (an agent is a database entity that performs processing of all aspects of a statement). There is no
"global scratchpad" to coordinate the sharing of scratchpad information between the agents. This is
especially important for situations where the database manager establishes multiple agents to process a
statement (in either a single partition or multiple partition database). In these cases, even though there
might only be a single reference to a routine in a statement, there could be multiple agents doing the
work, and each would have its own scratchpad. In a multiple partition database, where a statement
referencing a UDF is processing data on multiple partitions, and invoking the UDF on each partition, the
scratchpad would only apply to a single partition. As a result, there is a scratchpad on each partition
where the UDF is executed.
If the correct execution of a function depends on there being a single scratchpad per reference to the
function, then register the function as DISALLOW PARALLEL. This will force the function to run on a single
partition, thereby guaranteeing that only a single scratchpad will exist per reference to the function.
Because it is recognized that a UDF or method might require system resources, the UDF or method can be
defined with the FINAL CALL keyword. This keyword tells the database manager to call the UDF or
method at end-of-statement processing so that the UDF or method can release its system resources. It is
For UDFs or methods that use a scratchpad and are referenced in a subquery, the database manager
might make a final call, if the UDF or method is so specified, and refresh the scratchpad between
invocations of the subquery. You can protect yourself against this possibility, if your UDFs or methods are
ever used in subqueries, by defining the UDF or method with FINAL CALL and using the call-type
argument, or by always checking for the binary zero state of the scratchpad.
If you do specify FINAL CALL, note that your UDF or method receives a call of type FIRST. This could be
used to acquire and initialize some persistent resource.
Following is a simple Java example of a UDF that uses a scratchpad to compute the sum of squares of
entries in a column. This example takes in a column and returns a column containing the cumulative sum
of squares from the top of the column to the current row entry:
switch(getCallType())
{
case SQLUDF_FIRST_CALL:
// initialize data
sum = (inColumn * inColumn);
// save data into SCRATCHPAD area
dataOut.writeInt(sum);
byteArrayCounter = byteArrayOut.toByteArray();
for(i = 0; i < byteArrayCounter.length; i++)
{
scratchpad[i] = byteArrayCounter[i];
}
setScratchpad(scratchpad);
break;
case SQLUDF_NORMAL_CALL:
// read data from SCRATCHPAD area
sum = dataIn.readInt();
// work with data
Please note that there is a built-in database function that performs the same task as the SumOfSquares
UDF. This example was chosen to demonstrate the use of a scratchpad.
struct sql_scratchpad
{
sqlint32 length;
char data[100];
};
When defining its own structure for the scratchpad, a routine has two choices:
1. Redefine the entire scratchpad sql_scratchpad, in which case it needs to include an explicit length
field. For example:
struct sql_spad
{
sqlint32 length;
sqlint32 int_var;
sqlint64 bigint_var;
};
void SQL_API_FN routine( ..., struct sql_spad* scratchpad, ... )
{
/* Use scratchpad */
}
2. Redefine just the data portion of the scratchpad sql_scratchpad, in which case no length field is
needed.
struct spaddata
{
sqlint32 int_var;
sqlint64 bigint_var;
};
void SQL_API_FN routine( ..., struct sql_scratchpad* spad, ... )
{
struct spaddata* scratchpad = (struct spaddata*)spad→data;
/* Use scratchpad */
}
As the application cannot change the value in the length field of the scratchpad, there is no significant
benefit to coding the routine as shown in the first example. The second example is also portable between
computers with different word sizes, so it is the preferred way of writing the routine.
DB2SQL “1” • C/C++ • stored In addition to the parameters passed during invocation, the
on page 67 following arguments are passed to the stored procedure in the
• OLE procedures
following order:
• .NET
• A vector that contains a null indicator for each parameter on the
common
CALL statement.
language
runtime • The SQLSTATE to be returned to the database manager.
languages • The qualified name of the stored procedure.
• COBOL • The specific name of the stored procedure.
• The SQL diagnostic string to be returned to the database
manager.
If the DBINFO clause is specified in the CREATE PROCEDURE
statement, a dbinfo structure (it contains information about the
database) is passed to the stored procedure.
DB2GENERA • Java • UDFs This type of routine uses a parameter passing convention that is
L defined for use with Java methods. Unless you are developing
• stored table UDFs, UDFs with scratchpads, or need access to the
procedures dbinfo structure, use PARAMETER STYLE JAVA.
• methods
For PARAMETER STYLE DB2GENERAL routines, no additional
arguments to those specified in the routine invocation are passed.
GENERAL • C/C++ • stored A PARAMETER STYLE GENERAL WITH NULLS stored procedure
WITH NULLS procedures receives parameters from the CALL statement in the invoking
• .NET application or routine. Also included is a vector that contains a
common null indicator for each parameter on the CALL statement. If the
language DBINFO clause is specified in the CREATE PROCEDURE
runtime statement, a dbinfo structure (it contains information about the
languages database) is passed to the stored procedure.
• COBOL
GENERAL WITH NULLS is the equivalent of SIMPLE WITH NULLS
stored procedures for Db2 for z/OS.
XML data type values are represented in external routine code in the same way as CLOB data types.
When declaring external routine parameters of data type XML, the CREATE PROCEDURE and CREATE
FUNCTION statements that will be used to create the routines in the database must specify that the XML
data type is to be stored as a CLOB data type. The size of the CLOB value should be close to the size of the
XML document represented by the XML parameter.
The following CREATE PROCEDURE statement shows a CREATE PROCEDURE statement for an external
procedure implemented in the C programming language with an XML parameter named parm1:
Similar considerations apply when creating external UDFs, as shown in the following example:
XML data is materialized when passed to stored procedures as IN, OUT, or INOUT parameters. If you are
using Java stored procedures, the heap size (java_heap_sz configuration parameter) might need to be
increased based on the quantity and size of XML arguments, and the number of external stored
procedures that are being executed concurrently.
Within external routine code, XML parameter and variable values are accessed, set, and modified in the
same way as in database applications.
Procedure
1. Code the routine logic in the chosen programming language.
• For general information about external routines, routine features, and routine feature
implementation, see the topics that are referenced in the Prerequisites section.
• Use or import any header files that are required to support the execution of SQL statements.
• Declare variables and parameters correctly using programming language data types that map to Db2
SQL data types.
2. Parameters must be declared in accordance with the format required by the parameter style for the
chosen programming language. For more on parameters and prototype declarations see:
• “External routine parameter styles” on page 65
3. Build your code into a library or class file.
4. Copy the library or class file into the function directory on the database server. You can store
assemblies or libraries that are associated with routines in the function directory. To find out more
about the function directory, see the EXTERNAL clause of either of the following statements: CREATE
PROCEDURE or CREATE FUNCTION.
You can copy the assembly to another directory on the server if you wish, but to successfully invoke
the routine you must note the fully qualified path name of your assembly as you will require it for the
next step.
The assembly or library must be accessible on all physical hosts that are listed in the db2nodes.cfg
file. If you copied the assembly or library to a directory that is not located on a shared file system,
which is accessible to all hosts, then you must manually copy the file to the same location on each
host.
If your routine is written in Java, consider using the SQLJ.INSTALL_JAR built-in procedure to manage
the deployment of the routine implementation.
5. Execute either dynamically or statically the appropriate SQL language CREATE statement for the
routine type: CREATE PROCEDURE or CREATE FUNCTION.
What to do next
Writing routines
The three types of routines (procedures, UDFs, and methods) have much in common with regards to how
they are written.
The three routine types employ some of the same parameter styles, support the use of SQL through
various client interfaces (embedded SQL, CLI, and JDBC), and can all invoke other routines. To this end,
the following steps represent a single approach for writing routines.
There are some routine features that are specific to a routine type. For example, result sets are specific to
stored procedures, and scratchpads are specific to UDFs and methods. When you come across a step not
applicable to the type of routine you are developing, go to the step that follows it.
Before writing a routine, you must decide the following:
• The type of routine you need.
• The programming language you will use to write it.
• Which interface to use if you require SQL statements in your routine.
See also the topics on Security, Library and Class Management, and Performance considerations.
Procedure
To create a routine body, you must:
1. Applicable only to external routines. Accept input parameters from the invoking application or routine
and declare output parameters. How a routine accepts parameters is dependent on the parameter
style you will create the routine with. Each parameter style defines the set of parameters that are
passed to the routine body and the order that the parameters are passed.
For example, the following is a signature of a UDF body written in C (using sqludf.h) for PARAMETER
STYLE SQL:
2. Add the logic that the routine is to perform. Some features that you can employ in the body of your
routines are as follows:
• Calling other routines (nesting), or calling the current routine (recursion).
• In routines that are defined to have SQL (CONTAINS SQL, READS SQL, or MODIFIES SQL), the
routine can issue SQL statements. The types of statements that can be invoked is controlled by how
routines are registered.
• In external UDFs and methods, use scratchpads to save state from one call to the next.
• In SQL procedures, use condition handlers to determine the SQL procedure's behavior when a
specified condition occurs. You can define conditions based on SQLSTATEs.
3. Applicable only to stored procedures. Return one or more result sets. In addition to individual
parameters that are exchanged with the calling application, stored procedures have the capability to
return multiple result sets. Only SQL routines and CLI, ODBC, JDBC, and SQLJ routines and clients can
accept result sets.
Results
In addition to writing your routine, you also need to register it before you can invoke it. This is done with
the CREATE statement that matches the type of routine you are developing. In general, the order in which
you write and register your routine does not matter. However, the registration of a routine must precede
its being built if it issues SQL that references itself. In this case, for a bind to be successful, the routine's
registration must have already occurred.
Category DB2Types Classes DB2Type Data Type Database Data Type Informix Data Type .NET Data Type
and Structures
1 These data types are not supported as parameters in the .NET common language runtime routines.
2 A DB2ParameterClass.ParameterName property of the type DB2Type.Xml can accept variables of the
following types: String, byte[], DB2Xml, and XmlReader.
3 These data types are applicable only to Db2 for z/OS.
4 This data type is only supported for Db2 for z/OS, Version 9 and later releases and for Db2 Version 9.5 and
later releases.
It is clear that the parameter style SQL is implemented because of the extra null indicator parameter,
languageNullInd associated with the output parameter language, the parameters for passing the
SQLSTATE, the routine name, the routine specific name, and optional user-defined SQL error message.
Parameter keywords have been specified for the parameters as follows:
• In C# no parameter keyword is required for input only parameters.
• In C# the 'out' keyword indicates that the variable is an output parameter only, and that its value has
not been initialized by the caller.
• In C# the 'ref' keyword indicates that the parameter was initialized by the caller, and that the routine
can optionally modify this value.
See the .NET language specific documentation regarding parameter passing to learn about the parameter
keywords in that language.
Note: The database manager controls allocation of memory for all parameters and maintains CLR
references to all parameters passed into or out of a routine.
The .NET representation of a result set is a DB2DataReader object which can be returned from one of
the various execute calls of a DB2Command object. Any DB2DataReader object whose Close() method
has not explicitly been called prior to the return of the procedure, can be returned. The order in which
result sets are returned to the caller is the same as the order in which the DB2DataReader objects were
instantiated. No additional parameters are required in the function definition in order to return a result
set.
An understanding of how to create CLR routines will help you to perform the steps in the following
procedure for returning results from a CLR procedure.
• “Creating .NET CLR routines from the Db2 command window” on page 83
Procedure
To return a result set from a CLR procedure:
1. In the CREATE PROCEDURE statement for the CLR routine you must specify along with any other
appropriate clauses, the DYNAMIC RESULT SETS clause with a value equal to the number of result
sets that are to be returned by the procedure.
2. No parameter marker is required in the procedure declaration for a result set that is to be returned to
the caller.
3. In the .NET language implementation of your CLR routine, create a DB2Connection object, a
DB2Command object, and a DB2Transaction object. A DB2Transaction object is responsible for
rolling back and committing database transactions.
4. Initialize the Transaction property of the DB2Command object to the DB2Transaction object.
The CREATE METHOD statement with LANGUAGE CLR clause is not supported
You cannot create external methods for the database structured types that reference a CLR assembly.
The use of a CREATE METHOD statement that specifies the LANGUAGE clause with value CLR is not
supported.
• Review the “.NET common language runtime (CLR) routines” on page 75.
• Ensure that you have access to a database server, including instances and databases.
• Ensure that the operating system is at a version level that is supported by the database products.
• Ensure that the Microsoft .NET development software is at a version level that is supported for .NET CLR
routine development. Refer to “Support for external routine development in .NET CLR languages” on
page 75.
• Authority to execute the CREATE PROCEDURE or CREATE FUNCTION statement.
For a list of restrictions that are associated with CLR routines see:
• “Restrictions on .NET CLR routines” on page 82
The ways in which you can create .NET CLR routines follow:
• Using the graphical tool that is provided with the IBM Database Add-Ins for Microsoft Visual Studio
• Using the Db2 command window
It is easier to create .NET CLR routines using the IBM Database Add-Ins for Microsoft Visual Studio.
However, you can use the Db2 command window to create .NET CLR routines.
Procedure
• Visual Studio .NET when the IBM Database Add-Ins for Microsoft Visual Studio is also installed. When
the Add-In is installed, graphical tool that is integrated into Visual Studio .NET is available for
creating .NET CLR routines.
• Db2 command window
What to do next
Procedure
1. Code the routine logic in any CLR supported language.
• For general information about .NET CLR routines and .NET CLR routine features see the topics
referenced in the "Before you begin" section
• Use or import the IBM.Data.DB2 assembly if your routine will execute SQL.
• Declare host variables and parameters correctly using data types that map to SQL data types. For a
data type mapping between the database and .NET data types, see the following topic:
– “SQL data type representation in .NET CLR routines” on page 76
• Parameters and parameter null indicators must be declared with one of the supported parameter
styles and according to the parameter requirements for .NET CLR routines. Also, scratchpads for
UDFs, and the DBINFO class are passed into CLR routines as parameters. For more on parameters
and prototype declarations, see the following topic:
– “Parameters in .NET CLR routines” on page 78
• If the routine is a procedure and you want to return a result set to the caller of the routine, you do
not require any parameters for the result set. For more on returning result sets from CLR routines:
– “Returning result sets from .NET CLR procedures” on page 80
• Set a routine return value if required. CLR scalar functions require that a return value is set before
returning. CLR table functions require that a return code is specified as an output parameter for each
invocation of the table function. CLR procedures do not return with a return value.
2. Build your code into an intermediate language (IL) assembly to be executed by the CLR.
For information on how to build CLR .NET routines that access the databases, see the following topic:
• "Building common language runtime (CLR) .NET routines" in Developing ADO.NET and OLE DB
Applications
3. Copy the assembly into the database function directory on the database server. You can store
assemblies or libraries that are associated with database routines in the function directory. For more
information about the function directory, see the EXTERNAL clause of the CREATE PROCEDURE or
CREATE FUNCTION statement.
Procedure
• There are three ways to build .NET CLR routines:
– Using the graphical tool that is provided with the IBM Database Add-Ins for Microsoft Visual Studio
– Using sample batch files
– Entering commands from the Db2 command window
The sample build scripts and batch files for routines are designed for building database sample
routines (procedures and user-defined functions) as well as user created routines for a particular
operating system using the default supported compilers.
There is a separate set of sample build scripts and batch files for C# and Visual Basic. It is easier to
build .NET CLR routines using the graphical tools or the build scripts, which can be modified as
required. However, it is often helpful to know how to build routines from the Db2 command window.
Building .NET common language runtime (CLR) routine code using sample build scripts
Building .NET common language runtime (CLR) routine source code is a subtask of creating .NET CLR
routines. You can use the sample batch files that are provided with the database to build .NET CLR
routines more easily.
The sample build scripts can be used for source code with or without SQL statements. The build scripts
take care of the compilation, linking, and deployment of the built assembly to the function
directory.
As alternatives, you can build .NET CLR routines in Visual Studio .NET to simplify the task or you can issue
the commands in the sample build script manually.
You can use the programming-language specific sample build script bldrtn for building C# and Visual
Basic .NET CLR routines. They are located in the database sample directory along with sample programs:
bldrtn file-name
If the routines will be created in another database, enter the build script name, the source code file
name without any file extension, and the database name:
The script compiles and links the source code and produces an assembly. The script then copies
the assembly to the function directory on the database server
4. If this is not the first time that the source code file containing the routine implementations was
built, stop and restart the database to ensure the new version of the shared library is used by the
database. You can do this by entering db2stop followed by db2start on the command line.
Once you have successfully built the routine shared library and deployed it to the function directory on
the database server, you should complete the steps associated with the task of creating C and C++
routines.
Creating .NET CLR routines includes a step for executing the CREATE statement for each routine that was
implemented in the source code file. After routine creation is completed you can invoke your routines.
Procedure
To build a source code file that contains one or more .NET CLR routine code implementations:
1. Open the Db2 command window.
2. Navigate to the directory that contains your source code file.
3. Establish a connection with the database in which the routines are created.
4. Compile the source code file.
5. Link the source code file to generate a shared library. The linking process requires the use of compiler
link options that references the database include directory.
6. Copy the assembly file with the .DLL file suffix to the database function directory on the database
server.
7. If you are not building the source code file for the first time, you must stop and restart the database
manager to ensure that the new version of the shared library is used by the database manager. You
can issue the db2stop command followed by the db2start command to restart the database
manager.
Results
Once you successfully built and deployed the routine library, you can register the new routine in the
database by running the CREATE statement. The routine must be registered before you can call the new
routine.
Example
The following example builds a .NET CLR source code file. Steps are shown for both the myVBfile.vb
Visual Basic code file and the myCSfile.cs C# code file that contains routine implementations. The
routines are being built with the Microsoft .NET Framework on a Windows operating system to generate a
64-bit assembly.
1. Open the Db2 command window.
2. Navigate to the directory that contains your source code file.
3. Establish a connection with the database to which the routine is intended for.
C# example
===================
csc /out:myCSfile.dll /target:library
/reference:$DB2PATH%\bin\netf40\IBM.Data.DB2.dll myCSfile.cs
The compiler displays an output to indicate whether there are any errors.
5. Copy the shared library to the database function directory on the database server.
C# example
====================
rm -f ~HOME/sqllib/function/myCSfile.DLL
cp myCSfile $HOME/sqllib/function/myCSfile.DLL
This step ensures that the routine library is in the default directory where the database manager looks
for routine libraries.
6. Stop and restart the database manager.
db2stop
db2start
You can modify the sample build scripts that are provided in the sample subdirectory of the sqllib
directory to simplify building the .NET CLR routines.
Procedure
• Verify that a supported operating system for .NET CLR routine development is being used.
• Verify that both database server and database client are supported for the .NET CLR routine
development.
• Verify that supported Microsoft .NET Framework development software is being used.
• If routine creation failed:
– Verify that the user has the required authority and privileges to execute the CREATE PROCEDURE or
CREATE FUNCTION statement.
• If routine invocation failed:
– Verify that the user has authority to execute the routine. If an error (SQLCODE -551, SQLSTATE
42501), this is likely because the invoker does not have the EXECUTE privilege on the routine. This
privilege can be granted by any user with SECADM authority, ACCESSCTRL authority, or by any user
with EXECUTE WITH GRANT OPTION privilege on the routine.
Results
For more information on common errors related to .NET CLR routine creation and invocation, see:
• “Errors related to .NET CLR routines” on page 89
Example
The C# external code file
The examples show a variety of C# procedure implementations. Each example consists of two parts:
the CREATE PROCEDURE statement and the external C# code implementation of the procedure from
which the associated assembly can be built.
The C# source file that contains the procedure implementations of the following examples is named
gwenProc.cs and has the following format:
using System;
using System.IO;
using IBM.Data.DB2;
namespace bizLogic
{
class empOps
{ ...
// C# procedures
...
}
}
The file inclusions are indicated at the top of the file. The IBM.Data.DB2 inclusion is required if any
of the procedures in the file contain SQL. There is a namespace declaration in this file and a class
empOps that contains the procedures. The use of namespaces is optional. If a namespace is used, the
namespace must appear in the assembly path name provided in the EXTERNAL clause of the CREATE
PROCEDURE statement.
It is important to note the name of the file, the namespace, and the name of the class, that contains a
given procedure implementation. These names are important, because the EXTERNAL clause of the
CREATE PROCEDURE statement for each procedure must specify this information so that the
database manager can locate the assembly and class of the CLR procedure.
Example 1: C# parameter style GENERAL procedure
This example shows the following:
• CREATE PROCEDURE statement for a parameter style GENERAL procedure
• C# code for a parameter style GENERAL procedure
This procedure takes an employee ID and a current bonus amount as input. It retrieves the
employee's name and salary. If the current bonus amount is zero, a new bonus is calculated, based on
the employee's salary, and returned along with the employee's full name. If the employee is not
found, an empty string is returned.
salary = reader.GetDecimal(3);
if (bonus == 0)
{
if (salary > 75000)
{
bonus = salary * (Decimal)0.025;
}
else
{
bonus = salary * (Decimal)0.05;
}
}
}
else // Employee not found
{
empName = ""; // Set output parameter
}
reader.Close();
}
if (bonus == 0)
{
if (salary > 75000)
{
bonus = salary * (Decimal)0.025;
NullInds[1] = 0; // Return a non-NULL value
}
else
{
bonus = salary * (Decimal)0.05;
NullInds[1] = 0; // Return a non-NULL value
}
}
}
else // Employee not found
{
empName = "*sdq;; // Set output parameter
NullInds[2] = -1; // Return a NULL value
}
reader.Close();
}
}
if (bonus == 0)
{
if (salary > 75000)
{
bonus = salary * (Decimal)0.025;
bonusNullInd = 0; // Return a non-NULL value
}
else
{
bonus = salary * (Decimal)0.05;
bonusNullInd = 0; // Return a non-NULL value
}
}
}
else // Employee not found
{
empName = ""; // Set output parameter
empNameNullInd = -1; // Return a NULL value
}
reader.Close();
}
}
if (bonus == 0)
{
if (salary > 75000)
{
argv[1] = (Decimal)(salary * (Decimal)0.025);
NullInds[1] = (Int16)(0); // Return a non-NULL value
}
else
{
argv[1] = (Decimal)(salary * (Decimal)0.05);
NullInds[1] = (Int16)(0); // Return a non-NULL value
}
}
reader.Close();
}
}
Procedure
Use the following examples as references when making your own Visual Basic CLR UDFs:
• “The Visual Basic external code file” on page 98
• “Example 1: Visual Basic parameter style SQL table function” on page 99
• “Example 2: Visual Basic parameter style SQL scalar function” on page 100
Example
The Visual Basic external code file
The following examples show a variety of Visual Basic UDF implementations. The CREATE FUNCTION
statement is provided for each UDF with the corresponding Visual Basic source code from which the
associated assembly can be built. The Visual Basic source file that contains the functions declarations
used in the following examples is named gwenVbUDF.cs and has the following format:
using System;
using System.IO;
using IBM.Data.DB2;
Namespace bizLogic
...
' Class definitions that contain UDF declarations
' and any supporting class definitions
...
End Namespace
The function declarations must be contained in a class within a Visual Basic file. The use of
namespaces is optional. If a namespace is used, the namespace must appear in the assembly path
Class Person
' The class Person is a supporting class for
' the table function UDF, tableUDF, below.
name = newName
position = newPosition
salary = newSalary
End Sub
End Class
Class empOps
intRow = 0
Select callType
Case -2 ' Case SQLUDF_TF_FIRST:
Case -1 ' Case SQLUDF_TF_OPEN:
intRow = 1
scratchPad(0) = intRow ' Write to scratchpad
Case 0 ' Case SQLUDF_TF_FETCH:
intRow = scratchPad(0)
If intRow > staff.Length
sqlState = "02000" ' Return an error SQLSTATE
Else
' Generate a row in the output table
' based on the staff array data.
name = staff(intRow).GetName()
position = staff(intRow).GetPosition()
salary = (staff(intRow).GetSalary()) * factor
nameNullInd = 0
positionNullInd = 0
salaryNullInd = 0
End If
intRow = intRow + 1
scratchPad(0) = intRow ' Write scratchpad
End Sub
End Class
A simple query such as the following can be used to invoke the scalar function:
COUNT I1
----------- ----------
1 12
2 45
3 16
4 99
This scalar UDF is quite simple. Instead of returning just the count of the rows, you could use a scalar
function to format data in an existing column. For example you might append a string to each value in
an address column or you might build up a complex string from a series of input strings or you might
do a complex mathematical evaluation over a set of data where you must store an intermediate result.
Class empOps
Public Shared Sub CountUp(byVal input As Int32, _
byRef outCounter As Int32, _
byVal nullIndInput As Int16, _
byRef nullIndOutCounter As Int16, _
byRef sqlState As String, _
byVal qualName As String, _
byVal specName As String, _
byRef sqlMessageText As String, _
byVal scratchPad As Byte(), _
byVal callType As Int32)
Select callType
case -1 ' case SQLUDF_TF_OPEN_CALL
scratchPad(0) = counter
outCounter = counter
nullIndOutCounter = 0
case 0 'case SQLUDF_TF_FETCH_CALL:
counter = scratchPad(0)
counter = counter + 1
outCounter = counter
nullIndOutCounter = 0
scratchPad(0) = counter
case 1 'case SQLUDF_CLOSE_CALL:
End Class
Procedure
Use the following examples as references when making your own Visual Basic CLR procedures:
• “The Visual Basic external code file” on page 102
• “Example 1: Visual Basic parameter style GENERAL procedure” on page 103
• “Example 2: Visual Basic parameter style GENERAL WITH NULLS procedure” on page 104
• “Example 3: Visual Basic parameter style SQL procedure” on page 105
• “Example 4: Visual Basic parameter style GENERAL procedure returning a result set” on page 106
• “Example 5: Visual Basic parameter style SQL procedure accessing the dbinfo structure” on page 106
• “Example 6: Visual Basic procedure with PROGRAM TYPE MAIN style” on page 107
Example
The Visual Basic external code file
The examples show a variety of Visual Basic procedure implementations. Each example consists of
two parts: the CREATE PROCEDURE statement and the external Visual Basic code implementation of
the procedure from which the associated assembly can be built.
using System;
using System.IO;
using IBM.Data.DB2;
Namespace bizLogic
Class empOps
...
' Visual Basic procedures
...
End Class
End Namespace
The file inclusions are indicated at the top of the file. The IBM.Data.DB2 inclusion is required if any
of the procedures in the file contain SQL. There is a namespace declaration in this file and a class
empOps that contains the procedures. The use of namespaces is optional. If a namespace is used, the
namespace must appear in the assembly path name provided in the EXTERNAL clause of the CREATE
PROCEDURE statement.
It is important to note the name of the file, the namespace, and the name of the class, that contains a
given procedure implementation. These names are important, because the EXTERNAL clause of the
CREATE PROCEDURE statement for each procedure must specify this information so that the
database manager can locate the assembly and class of the CLR procedure.
Example 1: Visual Basic parameter style GENERAL procedure
This example shows the following:
• CREATE PROCEDURE statement for a parameter style GENERAL procedure
• Visual Basic code for a parameter style GENERAL procedure
This procedure takes an employee ID and a current bonus amount as input. It retrieves the
employee's name and salary. If the current bonus amount is zero, a new bonus is calculated, based on
the employee salary, and returned along with the employee's full name. If the employee is not found,
an empty string is returned.
salary = 0
myCommand = DB2Context.GetCommand()
myCommand.CommandText = _
"SELECT FIRSTNME, MIDINIT, LASTNAME, SALARY " _
+ "FROM EMPLOYEE " _
+ "WHERE EMPNO = '" + empId + "'"
myReader = myCommand.ExecuteReader()
If bonus = 0
If salary > 75000
bonus = salary * 0.025
Else
bonus = salary * 0.05
End If
End If
Else ' Employee not found
empName = "" ' Set output parameter
End If
myReader.Close()
End Sub
salary = 0
myReader = myCommand.ExecuteReader()
salary = myReader.GetDecimal(3)
If bonus = 0
If salary > 75000
bonus = Salary * 0.025
nullInds(1) = 0 'Return a non-NULL value
myReader.Close()
End If
End Sub
salary = 0
myReader = myCommand.ExecuteReader()
myReader.Close()
End If
End Sub
Example 4: Visual Basic parameter style GENERAL procedure returning a result set
This example shows the following:
• CREATE PROCEDURE statement for an external Visual Basic procedure returning a result set
• Visual Basic code for a parameter style GENERAL procedure that returns a result set
This procedure accepts the name of a table as a parameter. It returns a result set containing all the
rows of the table specified by the input parameter. This is done by leaving a DB2DataReader for a
given query result set open when the procedure returns. Specifically, if reader.Close() is not
executed, the result set will be returned.
myCommand = DB2Context.GetCommand()
End Sub
Example 5: Visual Basic parameter style SQL procedure accessing the dbinfo structure
This example shows the following:
• CREATE PROCEDURE statement for a procedure accessing the dbinfo structure
• Visual Basic code for a parameter style SQL procedure that accesses the dbinfo structure
To access the dbinfo structure, the DBINFO clause must be specified in the CREATE PROCEDURE
statement. No parameter is required for the dbinfo structure in the CREATE PROCEDURE statement
however a parameter must be created for it, in the external routine code. This procedure returns only
the value of the current database name from the dbname field in the dbinfo structure.
myReader = myCommand.ExecuteReader()
If bonus = 0
If salary > 75000
argv(1) = salary * 0.025
nullInds(1) = 0 ' Return a non-NULL value
Else
argv(1) = Salary * 0.05
nullInds(1) = 0 ' Return a non-NULL value
End If
End If
Else ' Employee not found
argv(2) = "" ' Set output parameter
nullInds(2) = -1 ' Return a NULL value
End If
myReader.Close()
End If
End Sub
Procedure
You can use the following example as references when you are making your own C# CLR procedures:
• “The C# external code file” on page 109
• “Example: C# parameter style GENERAL procedure with XML features” on page 110
using System;
using System.IO;
using System.Data;
using IBM.Data.DB2;
using IBM.Data.DB2Types;
namespace bizLogic
{
class empOps
{ ...
// C# procedures
...
}
}
The file inclusions are indicated at the top of the file. The IBM.Data.DB2 inclusion is required if any of
the procedures in the file contain SQL. The IBM.Data.DB2Types inclusion is required if any of the
procedures in the file contain parameters or variables of type XML. There is a namespace declaration in
this file and a class empOps that contains the procedures. The use of namespaces is optional. If a
//*************************************************************************
// Stored Procedure: xmlProc1
//
// Purpose: insert XML data into XML column
//
// Parameters:
//
// IN: inNum -- the sequence of XML data to be insert in xmldata table
// inXML -- XML data to be inserted
// OUT: outXML1 -- XML data returned - value retrieved using XQuery
// outXML2 -- XML data returned - value retrieved using SQL
//*************************************************************************
if (reader.Read())
{ outXML1 = reader.GetDB2Xml(0); }
else
{ outXML1 = DB2Xml.Null; }
reader.Close();
cmd.Close();
if (reader.Read())
{ outXML2 = reader.GetDB2Xml(0); }
else
{ outXML = DB2Xml.Null; }
reader.Close() ;
cmd.Close();
return;
}
Procedure
Use the following examples as references when making your own C procedures:
• “The C external code file” on page 112
• “Example 1: C parameter style SQL procedure with XML features” on page 112
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlda.h>
#include <sqlca.h>
#include <sqludf.h>
#include <sql.h>
#include <memory.h>
// C procedures
...
The file inclusions are indicated at the top of the file. There are no extra include files required for XML
support in embedded SQL routines.
It is important to note the name of the file and the name of the function that corresponds to the
procedure implementation. These names are important, because the EXTERNAL clause of the CREATE
PROCEDURE statement for each procedure must specify this information so that the database manager
can locate the library and entry point that corresponds to the C procedure.
//*************************************************************************
// Stored Procedure: xmlProc1
//
// Purpose: insert XML data into XML column
//
// Parameters:
//
// IN: inNum -- the sequence of XML data to be insert in xmldata table
// inXML -- XML data to be inserted
// OUT: out1XML -- XML data returned - value retrieved using XQuery
// out2XML -- XML data returned - value retrieved using SQL
//*************************************************************************
#ifdef __cplusplus
extern "C"
#endif
SQL_API_RC SQL_API_FN testSecA1(sqlint32* inNum,
SQLUDF_CLOB* inXML,
SQLUDF_CLOB* out1XML,
SQLUDF_CLOB* out2XML,
SQLUDF_NULLIND *inNum_ind,
SQLUDF_NULLIND *inXML_ind,
SQLUDF_NULLIND *out1XML_ind,
SQLUDF_NULLIND *out2XML_ind,
SQLUDF_TRAIL_ARGS)
{
char *str;
FILE *file;
exit:
return 0;
}
Procedure
• Use the following examples as references when making your own C# CLR UDFs:
– “The C# external code file” on page 114
– “Example 1: C# parameter style SQL table function” on page 115
– “Example 2: C# parameter style SQL scalar function” on page 116
Example
The C# external code file
The following examples show a variety of C# UDF implementations. The CREATE FUNCTION
statement is provided for each UDF with the corresponding C# source code from which the associated
assembly can be built. The C# source file that contains the functions declarations used in the
following examples is named gwenUDF.cs and has the following format:
using System;
using System.IO;
using IBM.Data.DB2;
namespace bizLogic
The function declarations must be contained in a class within a C# file. The use of namespaces is
optional. If a namespace is used, the namespace must appear in the assembly path name provided in
the EXTERNAL clause of the CREATE PROCEDURE statement. The IBM.Data.DB2. inclusion is
required if the function contains SQL.
Example 1: C# parameter style SQL table function
This example shows the following:
• CREATE FUNCTION statement for a parameter style SQL table function
• C# code for a parameter style SQL table function
This table function returns a table containing rows of employee data that was created from a data
array. There are two classes associated with this example. Class person represents the employees,
and the class empOps contains the routine table UDF that uses class person. The employee salary
information is updated based on the value of an input parameter. The data array in this example is
created within the table function itself on the first call of the table function. Such an array could have
also been created by reading in data from a text file on the file system. The array data values are
written to a scratchpad so that the data can be accessed in subsequent calls of the table function.
On each call of the table function, one record is read from the array and one row is generated in the
table that is returned by the function. The row is generated in the table, by setting the output
parameters of the table function to the desired row values. After the final call of the table function
occurs, the table of generated rows is returned.
class empOps
{
Int16 intRow = 0;
salary = 0;
name = position = "";
nameNullInd = positionNullInd = salaryNullInd = -1;
switch(callType)
{
case (-2): // Case SQLUDF_TF_FIRST:
break;
A simple query such as the following can be used to invoke the scalar function:
COUNT I1
----------- ----------
1 12
2 45
3 16
4 99
This scalar UDF is quite simple. Instead of returning just the count of the rows, you could use a scalar
function to format data in an existing column. For example you might append a string to each value in
an address column or you might build up a complex string from a series of input strings or you might
do a complex mathematical evaluation over a set of data where you must store an intermediate result.
class empOps
{
public static void CountUp( Int32 input,
out Int32 outCounter,
Int16 inputNullInd,
out Int16 outCounterNullInd,
ref String sqlState,
String funcName,
String specName,
ref String sqlMessageText,
Byte[] scratchPad,
Int32 callType)
{
Int32 counter = 1;
switch(callType)
{
case -1: // case SQLUDF_FIRST_CALL
scratchPad[0] = (Byte)counter;
outCounter = counter;
outCounterNullInd = 0;
break;
case 0: // case SQLUDF_NORMAL_CALL:
counter = (Int32)scratchPad[0];
counter = counter + 1;
outCounter = counter;
outCounterNullInd = 0;
Procedure
• “Include file required for C and C++ routine development (sqludf.h)” on page 120
• “Parameters in C and C++ routines” on page 121
Results
After having learned about the C and C++ characteristics, you might want to refer to:
• “Creating C and C++ routines” on page 155
• Macro definitions that can be used to test whether or not SQL arguments have null values.
To see how the various definitions, macros, and structures that are defined in the file sqludf.h are used,
see the C and C++ sample applications and routines.
It is strongly recommended that the parameter style SQL be used for all C and C++ routines. This
parameter style supports NULL values, provides a standard interface for reporting errors, as well as
supporting scratchpads and call types.
To specify the parameter style to be used for a routine, you must specify the PARAMETER STYLE clause in
the CREATE statement for the routine at routine creation time.
The parameter style must be accurately reflected in the implementation of the C or C++ routine code.
For more information about these parameter styles refer to: "Syntax for passing parameters to C and C++
routines".
SQL_API_RC SQL_API_FN
SQL_API_RC and SQL_API_FN are macros that specify the return type and calling convention for a C
or C++ procedure, which can vary across supported operating systems. The use of these macros is
required for C and C++ routines. The macros are declared in the embedded SQL application and
routine include file sqlsystm.h.
function-name
Name of the C or C++ function within the code file. This value does not have to be the same as the
name of the procedure that is specified within the corresponding CREATE PROCEDURE statement.
This value in combination with the library name however must be specified in the EXTERNAL NAME
clause to identify the correct function entry point within the library to be used. For C++ routines, the C
/****************************************************************
Routine: cstp
Parameters:
CODE TIP:
--------
Instead of coding the 'extra' parameters:
sqlstate, qualified name of the routine,
specific name of the routine, diagnostic message,
a macro SQLUDF_TRAIL_ARGS can be used instead.
This macro is defined in database include file sqludf.h
TIP EXAMPLE:
------------
The following is equivalent to the actual prototype
used that makes use of macro definitions included in
sqludf.h. The form actually implemented is simpler
and removes datatype concerns.
*****************************************************************/
sql_inParm = *inParm;
*outParm = (*inParm) + 1;
*outParmNullInd = 0;
return (0);
}
The create procedure statement cproc assumes that the C or C++ procedure implementation is in a
library file that is named c_rtns and a function named cstp.
SQL_API_RC SQL_API_FN
SQL_API_RC and SQL_API_FN are macros that specify the return type and calling convention for a C
or C++ user-defined function, which can vary across supported operating systems. The use of these
macros is required for C and C++ routines. The macros are declared in embedded SQL application and
routine include file sqlsystm.h.
function-name
Name of the C or C++ function within the code file. This value does not have to be the same as the
name of the function specified within the corresponding CREATE FUNCTION statement. This value in
combination with the library name however must be specified in the EXTERNAL NAME clause to
identify the correct function entry point within the library to be used. For C++ routines, the C++
compiler applies type decoration to the entry point name. Either the type decorated name needs to be
specified in the EXTERNAL NAME clause, or the function declaration within the source code file should
be prefixed with extern "C" as shown in the following example: extern "C" SQL_API_RC
SQL_API_FN OutLanguage( char *, sqlint16 *, char *, char *, char *, char *);
SQL-arguments
C or C++ arguments that correspond to the set of SQL parameters specified in the CREATE FUNCTION
statement.
SQL-argument-inds
For each SQL-argument a null indicator parameter is required to specify whether the parameter value
is intended to be interpreted within the routine implementation as a NULL value in SQL. Null indicators
must be specified with data type SQLUDF_NULLIND. This data type is defined in embedded SQL
routine include file sqludf.h.
SQLUDF_TRAIL_ARGS
A macro defined in embedded SQL routine include file sqludf.h that once expanded defines the
additional trailing arguments required for a complete parameter style SQL signature. There are two
macros that can be used: SQLUDF_TRAIL_ARGS and SQLUDF_TRAIL_ARGS_ALL.
SQLUDF_TRAIL_ARGS when expanded, as defined in sqludf.h, is equivalent to the addition of the
following routine arguments:
SQLUDF_CHAR *sqlState,
SQLUDF_CHAR qualName,
SQLUDF_CHAR specName,
SQLUDF_CHAR *sqlMessageText,
In general these arguments are not required or generally used as part of user-defined function logic.
They represent the output SQLSTATE value to be passed back to the function invoker, the input fully
qualified function name, input function specific name, and output message text to be returned with
SQLUDF_CHAR qualName,
SQLUDF_CHAR specName,
SQLUDF_CHAR sqlMessageText,
SQLUDF_SCRAT *scratchpad
SQLUDF_CALLT *callType
If the UDF CREATE statement includes the SCRATCHPAD clause or the FINAL CALL clause, then the
macro SQLUDF_TRAIL_ARGS_ALL must be used. In addition to arguments provided with
SQLUDF_TRAIL_ARGS, this macro also contains pointers to a scratchpad structure, and a call type
value.
The following is an example of a simple C or C++ UDF that returns in an output parameter the value of the
product of its two input parameter values:
The corresponding CREATE FUNCTION statement that can be used to create this UDF could be:
The preceding SQL statement assumes that the C or C++ function is in a library file in the function
directory named c_rtns.
SQL_STRUCTURE sqludf_dbinfo
{
unsigned short dbnamelen; /* Database name length */
unsigned char dbname[SQLUDF_MAX_IDENT_LEN]; /* Database name */
unsigned short authidlen; /* Authorization ID length */
unsigned char authid[SQLUDF_MAX_IDENT_LEN]; /* Authorization ID */
union db_cdpg codepg; /* Database code page */
unsigned short tbschemalen; /* Table schema name length */
unsigned char tbschema[SQLUDF_MAX_IDENT_LEN]; /* Table schema name */
unsigned short tbnamelen; /* Table name length */
unsigned char tbname[SQLUDF_MAX_IDENT_LEN]; /* Table name */
unsigned short colnamelen; /* Column name length */
unsigned char colname[SQLUDF_MAX_IDENT_LEN]; /* Column name */
unsigned char ver_rel[SQLUDF_SH_IDENT_LEN]; /* Database version/release */
unsigned char resd0[2]; /* Alignment */
sqluint32 platform; /* Platform */
unsigned short numtfcol; /* # of entries in TF column*/
/* List array */
unsigned char resd1[2]; /* Reserved */
sqluint32 procid; /* Current procedure ID */
unsigned char resd2[32]; /* Reserved */
unsigned short *tfcolumn; /* Tfcolumn to be allocated */
/* dynamically if a table */
/* function is defined; */
/* else a NULL pointer */
char *appl_id; /* Application identifier */
sqluint32 dbpartitionnum; /* Database partition number*/
/* where routine executed */
Although not all of the fields in the dbinfo structure might be useful within a routine, several of the
values in the structure fields might be useful when formulating diagnostic error message information. For
example, if an error occurs within a routine, it might be useful to return the database name, database
name length, the database code page, the current authorization ID, and the length of the current
authorization ID.
To reference the sqludf_dbinfo structure in a LANGUAGE C routine implementation:
• Add the DBINFO clause to the CREATE statement that defines the routine.
• Include the sqludf.h header file at the top of the file containing the routine implementation.
• Add a parameter of type sqludf_dbinfo to the routine signature in the position specified by the
parameter style used.
/***************************************************************
Routine: DbinfoExample
*salary = dbinfo_outsalary;
/* Copy values from the DBINFO structure into the output parameters
You must explicitly null-terminate the strings.
Information such as the database name, and the version of the
database product can be found in the DBINFO structure as well as
other information fields. */
return 0;
return_error:
{
*outSqlError = SQLCODE;
EXEC SQL WHENEVER SQLERROR CONTINUE;
return 0;
}
} /* DbinfoExample function */
#ifdef __cplusplus
extern "C"
#endif
void SQL_API_FN ScratchpadScUDF(SQLUDF_INTEGER *outCounter,
SQLUDF_SMALLINT *counterNullInd,
SQLUDF_TRAIL_ARGS_ALL)
{
struct scalar_scratchpad_data *pScratData;
*outCounter = pScratData->counter;
*counterNullInd = 0;
} /* ScratchpadScUDF */
The SQLUDF_TRAIL_ARGS_ALL macro expands to define other parameter values including one called
SQLUDF_SCRAT that defines a buffer parameter to be used as a scratchpad. When the scalar function is
invoked for a set of values, for each time the scalar function is invoked, the buffer is passed as a
parameter to the function. The buffer can be used to be accessed
The total number of arguments to the function is specified by the value of argc. The argument values are
passed as array elements within the argv array. The number and order of the arguments depends on the
PARAMETER STYLE clause value specified in the CREATE PROCEDURE statement.
As an example, consider the following CREATE PROCEDURE statement for a C procedure specified to
have a PROGRAM TYPE MAIN style and the recommended PARAMETER STYLE SQL:
The routine signature implementation that corresponds to this CREATE PROCEDURE statement follows:
//*****************************************************
// Stored Procedure: MainExample
//
// SQL parameters:
// IN: argv[1] - job (char[8])
// OUT: argv[2] - salary (double)
//*****************************************************
SQL_API_RC SQL_API_FN MainExample(int argc, char **argv)
{
...
}
Because PARAMETER STYLE SQL is used, in addition to the SQL parameter values passed at procedure
invocation time, the additional parameters required for that style are also passed to the routine.
Parameter values can be accessed by referencing the argv array element of interest within the source
code. For the example given previously, the argc and the argv array elements contain the following values:
1<=n<=255
SQLUDF_CHAR
CHAR(n) FOR BIT DATA char[n] where n is large enough Fixed-length, not null-terminated character
to hold the data string
1<=n<=255
SQLUDF_CHAR
1<=n<=32 672
SQLUDF_VARCHAR
1<=n<=32 672
SQLUDF_VARCHAR_FBD
1<=n<=32 700
SQLUDF_LONG
SQLUDF_CLOB
1<=n<=255
SQLUDF_BINARY
1<=n<=32 672
SQLUDF_VARBINARY
SQLUDF_BLOB
(VALUES(CURRENT TIMESTAMP(0))
1
-------------------
2008-07-09-14.48.36
1 record(s) selected.
1 record(s) selected.
(VALUES(CURRENT TIMESTAMP(12))
1
-------------------
2008-07-09-14.48.36.123456789012
1 record(s) selected.
1<=n<=127
SQLUDF_GRAPH
1<=n<=16 336
SQLUDF_GRAPH
1<=n<=16 350
SQLUDF_LONGVARG
SQLUDF_DBCLOB
SQLUDF_CLOB
Note: XML data types can only be implemented as CLOB data types in external routines implemented in C
or C++.
Note: The following data types are only available in the DBCS or EUC environment when precompiled with
the WCHARTYPE NOCONVERT option:
• GRAPHIC(n)
• VARGRAPHIC(n)
• LONG VARGRAPHIC
• DBCLOB(n)
In this case, the routine must be written to generate a SMALLINT, as defined later in this section. Note
that the CAST FROM data type must be castable to the RETURNS data type, therefore, it is not possible to
arbitrarily choose another data type.
The following is a list of the SQL types and their C/C++ language representations. It includes information
on whether each type is valid as a parameter or a result. Also included are examples of how the types
could appear as an argument definition in your C or C++ language routine:
• SMALLINT
Valid. Represent in C as SQLUDF_SMALLINT or sqlint16.
Example:
When defining integer routine parameters, consider using INTEGER rather than SMALLINT because the
database does not promote INTEGER arguments to SMALLINT. For example, suppose you define a UDF
as follows:
If you invoke the SIMPLE function using INTEGER data, (... SIMPLE(1)...), you will receive an
SQLCODE -440 (SQLSTATE 42884) error indicating that the function was not found, and end-users of
this function might not perceive the reason for the message. In the preceding example, 1 is an
INTEGER, so you can either cast it to SMALLINT or define the parameter as INTEGER.
• INTEGER or INT
Valid. Represent in C as SQLUDF_INTEGER or sqlint32. You must #include sqludf.h or
#include sqlsystm.h to pick up this definition.
Example:
• BIGINT
Valid. Represent in C as SQLUDF_BIGINT or sqlint64.
The database defines the sqlint64 C language type to overcome differences between definitions of
the 64-bit signed integer in compilers and operating systems. You must #include sqludf.h or
#include sqlsystm.h to pick up the definition.
• REAL or FLOAT(n) where 1 <= n <= 24
Valid. Represent in C as SQLUDF_REAL or float.
Example:
• DECIMAL(p,s) or NUMERIC(p,s)
Not valid because there is no C language representation. If you want to pass a decimal value, you must
define the parameter to be of a data type castable from DECIMAL (for example CHAR or DOUBLE) and
explicitly cast the argument to this type. In the case of DOUBLE, you do not need to explicitly cast a
decimal argument to a DOUBLE parameter, because the database promotes it automatically.
Example:
Suppose you have two columns, WAGE as DECIMAL(5,2) and HOURS as DECIMAL(4,1), and you wish to
write a UDF to calculate weekly pay based on wage, number of hours worked and some other factors.
The UDF could be as follows:
For the preceding UDF, the first two parameters correspond to the wage and number of hours. You
invoke the UDF WEEKLY_PAY in your SQL select statement as follows:
Note that no explicit casting is required because the DECIMAL arguments are castable to DOUBLE.
Alternatively, you could define WEEKLY_PAY with CHAR arguments as follows:
Observe that explicit casting is required because DECIMAL arguments are not promotable to VARCHAR.
An advantage of using floating point parameters is that it is easy to perform arithmetic on the values in
the routine; an advantage of using character parameters is that it is always possible to exactly represent
the decimal value. This is not always possible with floating point.
• CHAR(n) or CHARACTER(n) with or without the FOR BIT DATA modifier.
Valid. Represent in C as SQLUDF_CHAR or char...[n+1] (this is a C null-terminated string).
Example:
Input routine parameters of data type CHAR are always automatically null terminated. For a CHAR(n)
input parameter, where n is the length of the CHAR data type, n bytes of data are moved to the buffer in
the routine implementation and the character in the n + 1 position is set to the ASCII null terminator
character (X'00').
Output parameters of procedures and return values of functions of data type CHAR must be explicitly
null terminated by the routine. For a return value of a UDF specified by the RETURNS clause, such as
RETURNS CHAR(n), or a procedure output parameter specified as CHAR(n), where n is the length of the
CHAR value, a null terminator character must exist within the first n+1 bytes of the buffer. If a null
terminator is found within the first n+1 bytes of the buffer, the remaining bytes, up to byte n, are set to
ASCII blank characters X'20'). If no null terminator is found, an SQL error (SQLSTATE 39501) results.
For input and output parameters of procedures or function return values of data type CHAR that also
specify the FOR BIT DATA clause, which indicates that the data is to be manipulated in its binary form,
null terminators are not used to indicate the end of the parameter value. For either a RETURNS CHARn)
FOR BIT DATA function return value or a CHAR(n) FOR BIT DATA output parameter, the first n bytes of
the buffer are copied over regardless of any occurrences of string null terminators within the first n
bytes. Null terminator characters identified within the buffer are ignored as null terminators and instead
are simply treated as normal data.
Exercise caution when using the normal C string handling functions in a routine that manipulates a FOR
BIT DATA value, because many of these functions look for a null terminator to delimit a string argument
and null terminators (X'00') can legitimately appear in the middle of a FOR BIT DATA value. Using the C
functions on FOR BIT DATA values might cause the undesired truncation of the data value.
When defining character routine parameters, consider using VARCHAR rather than CHAR as the
database does not promote VARCHAR arguments to CHAR and string literals are automatically
considered as VARCHARs. For example, suppose you define a UDF as follows:
If you invoke the SIMPLE function using VARCHAR data, (... SIMPLE(1,'A')...), you will receive
an SQLCODE -440 (SQLSTATE 42884) error indicating that the function was not found, and end-users of
this function might not perceive the reason for the message. In the preceding example, 'A' is
VARCHAR, so you can either cast it to CHAR or define the parameter as VARCHAR.
• VARCHAR(n) FOR BIT DATA or LONG VARCHAR with or without the FOR BIT DATA modifier.
Valid. Represent VARCHAR(n) FOR BIT DATA in C as SQLUDF_VARCHAR_FBD. Represent LONG
VARCHAR in C as SQLUDF_LONG. Otherwise represent these two SQL types in C as a structure similar to
the following from the sqludf.h include file:
struct sqludf_vc_fbd
{
unsigned short length; /* length of data */
char data[1]; /* first char of data */
};
The [1] indicates an array to the compiler. It does not mean that only one character is passed; because
the address of the structure is passed, and not the actual structure, it provides a way to use array logic.
These values are not represented as C null-terminated strings because the null-character could
legitimately be part of the data value. The length is explicitly passed to the routine for parameters using
the structure variable length. For the RETURNS clause, the length that is passed to the routine is the
length of the buffer. What the routine body must pass back, using the structure variable length, is the
actual length of the data value.
Example:
• DATE
Valid. Represent in C same as SQLUDF_DATE or CHAR(10), that is as char...[11]. The date value is
always passed to the routine in ISO format:
yyyy-mm-dd
Example:
The characters for the DATE, TIME, and TIMESTAMP return values must be in the defined form to avoid
misinterpretation of the value by the database. For example, 2001-04-03 can be interpreted as April 3
even if March 4 is intended.
• TIME
Valid. Represent in C same as SQLUDF_TIME or CHAR(8), that is, as char...[9]. The time value is
always passed to the routine in ISO format:
hh.mm.ss
Example:
• TIMESTAMP
Valid. Represent in C as SQLUDF_STAMP or as CHAR(19) - CHAR(32), that is, as char[20] to
char[33]. The timestamp value has the following format:
yyyy-mm-dd-hh.mm.ss.nnnnnnnnnnnn
where:
yyyy
Represents the year.
mm
Represents the month.
dd
Represents the day.
hh
Represents the hour.
mm
Represents the minutes.
ss
Represents the seconds.
(VALUES(CURRENT TIMESTAMP(0))
1
-------------------
2008-07-09-14.48.36
1 record(s) selected.
1 record(s) selected.
(VALUES(CURRENT TIMESTAMP(12))
1
-------------------
2008-07-09-14.48.36.123456789012
1 record(s) selected.
The following are variable declarations that can hold a TIMESTAMP(12) value:
• GRAPHIC(n)
Valid. Represent in C as SQLUDF_GRAPH or sqldbchar[n+1]. (This is a null-terminated graphic
string). Note that you can use wchar_t[n+1] on operating systems where wchar_t is defined to be 2
bytes in length; however, sqldbchar is recommended.
For a GRAPHIC(n) parameter, the database moves n double-byte characters to the buffer and sets the
following two bytes to null. Data passed from the database to a routine is in DBCS format, and the result
passed back is expected to be in DBCS format. This behavior is the same as using the WCHARTYPE
NOCONVERT precompiler option. For a RETURNS GRAPHIC(n) value or an output parameter of a stored
procedure, the database looks for an embedded GRAPHIC null CHAR, and if it finds it, pads the value
out to n with GRAPHIC blank characters.
When you define graphic routine parameters, consider using VARGRAPHIC rather than GRAPHIC as the
database do not promote VARGRAPHIC arguments to GRAPHIC. For example, suppose that you define
a routine as follows:
• VARGRAPHIC(n)
Valid. Represent in C as SQLUDF_GRAPH or sqldbchar[n+1]. (This is a null-terminated graphic
string). Note that you can use wchar_t[n+1] on operating systems where wchar_t is defined to be 2
bytes in length; however, sqldbchar is recommended.
For a VARGRAPHIC(n) parameter, the database places a graphic null in the (k+1) position, where k is the
length of the particular occurrence. A graphic null refers to the situation where all the bytes of the last
character of the graphic string contain binary zeros ('\0's). Data passed from the database to a routine is
in DBCS format, and the result passed back is expected to be in DBCS format. This behavior is the same
as using the WCHARTYPE NOCONVERT precompiler option. For a RETURNS VARGRAPHIC(n) value or an
output parameter of a stored procedure, the routine body must delimit the actual value with a graphic
null, because the database determines the result length from this graphic null character.
Example:
• LONG VARGRAPHIC
Valid. Represent in C as SQLUDF_LONGVARG or a structure:
struct sqludf_vg
{
unsigned short length; /* length of data */
sqldbchar data[1]; /* first char of data */
};
Note that in the preceding structure, you can use wchar_t in place of sqldbchar on operating
systems where wchar_t is defined to be 2 bytes in length, however, the use of sqldbchar is
recommended.
The [1] merely indicates an array to the compiler. It does not mean that only one graphic character is
passed. Because the address of the structure is passed, and not the actual structure, it provides a way
to use array logic.
These are not represented as null-terminated graphic strings. The length, in double-byte characters, is
explicitly passed to the routine for parameters using the structure variable length. Data passed from
the database to a routine is in DBCS format, and the result passed back is expected to be in DBCS
format. This behavior is the same as using the WCHARTYPE NOCONVERT precompiler option. For the
RETURNS clause or an output parameter of a stored procedure, the length that is passed to the routine
is the length of the buffer. What the routine body must pass back, using the structure variable length,
is the actual length of the data value, in double byte characters.
Example:
• BINARY
Valid. Represent in C as SQLUDF_BINARY.
Example:
Input routine parameters of data type BINARY are always automatically null terminated. For a
BINARY(n) input parameter where n is the length of the BINARY data type, n bytes of the data are
struct sqludf_vc_fbd
{
unsigned short length; /* length of data */
char data[1]; /* first char of data */
};
The [1] indicates an array to the compiler. It does not mean that only one character is passed; because
the address of the structure is passed, and not the actual structure, it provides a way to use array logic.
These values are not represented as C null-terminated strings because the null-character could
legitimately be part of the data value. The length is explicitly passed to the routine for parameters using
the structure variable length. For the RETURNS clause, the length that is passed to the routine is the
length of the buffer. What the routine body must pass back, using the structure variable length, is the
actual length of the data value.
Example:
struct sqludf_lob
{
sqluint32 length; /* length in bytes */
char data[1]; /* first byte of lob */
};
The [1] merely indicates an array to the compiler. It does not mean that only one character is passed;
because the address of the structure is passed, and not the actual structure, it provides a way to use
array logic.
These are not represented as C null-terminated strings. The length is explicitly passed to the routine for
parameters using the structure variable length. For the RETURNS clause or an output parameter of a
stored procedure, the length that is passed back to the routine, is the length of the buffer. What the
routine body must pass back, using the structure variable length, is the actual length of the data value.
Example:
• DBCLOB(n)
Valid. Represent in C as SQLUDF_DBCLOB or a structure:
struct sqludf_lob
{
sqluint32 length; /* length in graphic characters */
sqldbchar data[1]; /* first byte of lob */
};
• Distinct Types
Valid or invalid depending on the base type. Distinct types will be passed to the UDF in the format of
the base type of the UDT, so can be specified if and only if the base type is valid.
Example:
• XML
Valid. Represent in C as SQLUDF_XML or in the way as a CLOB data type is represented; that is with a
structure:
struct sqludf_lob
{
sqluint32 length; /* length in bytes */
char data[1]; /* first byte of lob */
};
The [1] merely indicates an array to the compiler. It does not mean that only one character is passed;
because the address of the structure is passed, and not the actual structure, it provides a way to use
array logic.
These are not represented as C null-terminated strings. The length is explicitly passed to the routine for
parameters using the structure variable length. For the RETURNS clause or an output parameter of a
stored procedure, the length that is passed back to the routine, is the length of the buffer. What the
routine body must pass back, using the structure variable length, is the actual length of the data value.
Example:
The assignment and access of XML parameter and variable values in C and C++ external routine code is
done in the same way as for CLOB values.
• Distinct Types AS LOCATOR, or any LOB type AS LOCATOR
Valid for parameters and results of UDFs and methods. It can only be used to modify LOB types or
any distinct type that is based on a LOB type. Represent in C as SQLUDF_LOCATOR or a four byte
integer.
• Structured Types
Valid for parameters and results of UDFs and methods where an appropriate transform function exists.
Structured type parameters will be passed to the function or method in the result type of the FROM SQL
transform function. Structured type results will be passed in the parameter type of the TO SQL
transform function.
SQL-argument SQL-argument-ind
specific-name diagnostic-message
scratchpad call-type
dbinfo
SQL-argument SQL-argument-ind-array
specific-name diagnostic-message
dbinfo
dbinfo
SQL-argument
dbinfo
SQL-argument SQL-argument-ind-array
Note: For UDFs and methods, PARAMETER STYLE SQL is equivalent to PARAMETER STYLE DB2SQL.
The arguments for the PARAMETER STYLE SQL, PARAMETER STYLE GENERAL, and PARAMETER STYLE
GENERAL WITH NULL are described as follows:
SQL-argument...
Each SQL-argument argument represents one input or output value that is defined when the routine
was created. The list of arguments is determined as follows:
• For a scalar function, one argument for each input parameter to a function followed by one SQL-
argument argument for the result of a function.
• For a table function, one argument for each input parameter to a function followed by one SQL-
argument argument for each column in the result table of a function.
• For a method, one SQL-argument argument for the subject type of a method, then one argument for
each input parameter to a method followed by one SQL-argument for the result of a method.
• For a stored procedure, one SQL-argument argument for each parameter to a stored procedure.
Each SQL-argument argument is used as follows:
• Input parameter of a function or method, subject type of a method, or an IN parameter of a stored
procedure.
The input argument is set by the database manager before the routine is called. The value of each of
these arguments is taken from the expression that is specified in the routine invocation. It is
expressed in the data type of the corresponding parameter definition in the CREATE statement.
• Result of a function, method, or an OUT parameter of a stored procedure.
The output argument is set by a routine before it is returned to the database manager. The database
manager allocates the buffer and passes its address to a routine. The routine puts the result value
into the buffer. Enough buffer space is allocated by the database manager to contain the value that
is expressed in the data type. For character types and LOBs, the maximum size as defined in the
create statement is allocated.
For scalar functions and methods, the result data type is defined in the CAST FROM clause. If the
CAST FROM clause is not present, then the result data type is defined in the RETURNS clause.
For table functions, the database manager defines a performance optimization where every defined
column does not have to be returned to the database manager. If you write your UDF to take
advantage of this feature, it returns only the columns that are required by the statement, which
references the table function. For example, consider a CREATE FUNCTION statement for a table
function that is defined with 100 result columns. If a statement that references the function is only
interested in two columns, optimization by the database manager enables the UDF to return only
those two columns for each row and not spend time on the other 98 columns. For more information,
see the dbinfo argument content.
For each value returned, the routine returns bytes that are required for the data type and length of
the result. Maximums are defined during the creation of the routine's catalog entry. An overwrite by
the routine can cause unpredictable results or an abnormal termination.
schema.routine
PABLO.BLOOP WILLIE.FINDSTRING
You can use the schema.routine form to have same routines under a different schema name.
Although it is possible to include the period in object names and schema names, avoid use of the
period in object names to avoid confusion. For example, if you have a routine name that is passed as
the OBJ.OP.ROTATE value, it is difficult to distinguish the schema name or the routine name.
The routine-name value is in form of VARCHAR(257).
specific-name
The specific-name argument is set by the database manager before a routine is called. It is the
specific name that is passed from the database manager to a routine.
The following lists two examples of the specific name value:
WILLIE_FIND_FEB99 SQL9904281052440430
The first example of the specific name value is provided by the user in the CREATE statement. The
second example of the specific name value is generated by the database manager from the current
timestamp when the user does not specify the specific name value.
As with the routine-name argument, the specific name value is used to clearly identify the routine.
The specific-name value is in form of VARCHAR(18).
diagnostic-message
The diagnostic-message argument is set by the routine before it is returned to the database manager.
The routine can use the diagnostic-message argument to insert a message text in a database
message.
Routines can include descriptive information in the diagnostic-message argument with the sqlstate
argument when an error or a warning is encountered. The database manager includes this information
as a token in its message.
The database manager sets the first character to null before a routine is called. The diagnostic
message that is returned by the routine is treated as a C null-terminated string. The diagnostic
message string is included in the SQLCA structure as a token for the error condition. The first part of
the diagnostic message string appears in the SQLCA or CLP message. However, the actual number of
characters that appear depends on the lengths of the other tokens. The database manager might
truncate the tokens to conform to the total token length limit that is imposed by the SQLCA structure.
Avoid use of X'FF' in the diagnostic message string. The X'FF' value is used to delimit tokens in the
SQLCA structure.
You must ensure that the routine only returns texts that fits in the VARCHAR(70) buffer that is passed
to it. An overwrite by the routine can cause unpredictable results or an abend.
The database manager assumes that any message tokens returned from the routine to the database
manager are in the same code page as the routine. You must ensure that the code page that is set in
the database manager is same as the routine. If you use the 7-bit invariant ASCII subset, your routine
can return the message tokens in any code page.
The diagnostic-message value is in form of VARCHAR(70).
scratchpad
The scratchpad argument is set by the database manager before an UDF or a method is called. It is
only present for functions and methods that specified the SCRATCHPAD keyword during registration.
The scratchpad argument is a structure, which is similar to the sqllob data structure and contains
the following elements:
• An integer field that contains the length of the scratchpad. Changing the length of the scratchpad
results in SQLCODE -450 (SQLSTATE 39501)
x.y.ts
where the x and y values vary by connection type, but the ts value represents a 12 character time
stamp value of the form YYMMDDHHMMSS. The ts value ensures uniqueness of the string.
Example: *LOCAL.db2inst.980707130144
C++ compilers type-decorate or 'mangle' function names by default, where the argument type names are
appended to their function names, as in func__Fi and func__Fc for the two earlier examples. The
mangled names are different on each operating system, so code that explicitly uses a mangled name is
not portable.
On Windows operating systems, the type-decorated function name can be determined from the .obj
(object) file.
With the Microsoft Visual C++ compiler on Windows, you can use the dumpbin command to determine
the type-decorated function name from the .obj (object) file, as follows:
where myprog.o is your program object file, and myfunc is the function in the program source file.
The output that is produced by all of these commands includes a line with the mangled function name.
The following nm command output example contains the mangled function name:
Once you obtained the mangled function name from one of the preceding commands, you can use it in the
appropriate command.
When you register a routine with the CREATE statement, the EXTERNAL NAME clause must specify the
mangled function name. The following example registers the mangled function name with use of the
EXTERNAL NAME clause:
If your routine library does not contain overloaded C++ function names, you have the option of using
extern "C" to force the compiler to not type-decorate function names. You can always overload the
SQL function names that are given to UDFs since the database manager resolves what library function to
call based on the function name and the parameter it takes.
#include <string.h>
#include <stdlib.h>
#include "sqludf.h"
/*---------------------------------------------------------------------*/
/* function fold: output = input string is folded at point indicated */
/* by the second argument. */
/* inputs: CLOB, input string */
/* LONG position to fold on */
/* output: CLOB folded string */
/*---------------------------------------------------------------------*/
extern "C" void fold(
SQLUDF_CLOB *in1, /* input CLOB to fold */
...
...
}
/* end of UDF: fold */
/*---------------------------------------------------------------------*/
/* function find_vowel: */
/* returns the position of the first vowel. */
/* returns error if no vowel. */
/* defined as NOT NULL CALL */
/* inputs: VARCHAR(500) */
/* output: INTEGER */
/*---------------------------------------------------------------------*/
extern "C" void findvwl(
SQLUDF_VARCHAR *in, /* input smallint */
...
...
}
/* end of UDF: findvwl */
The fold and findvwl UDFs are not type-decorated by the compiler, and they must be registered in the
CREATE FUNCTION statement with their plain names. Similarly, if a C++ stored procedure or method is
coded with extern "C", its undecorated function name would be used in the CREATE statement.
Procedure
1. Code the routine logic in the chosen programming language: C or C++.
• Include any C or C++ header files that are required for additional C functionality and the database
header files for C or C++ that are required for SQL data type and SQL execution support. Include the
following header files:
– memory.h
– sql.h
– sqlca.h
– sqlda.h
– sqludf.h
• A routine parameter signature must be implemented using one of the supported parameter styles. It
is strongly recommended that parameter style SQL be used for all C and C++ routines. Scratchpads
and dbinfo structures are passed into C and C++ routines as parameters. For more on parameter
signatures and parameter implementations see:
– “Parameters in C and C++ routines” on page 121
– “Parameter style SQL C and C++ procedures” on page 122
– “Parameter style SQL C and C++ functions” on page 125
• Declare host variables and parameter markers in the same manner as is done for embedded SQL C
and C++ applications. Be careful to correctly use data types that map to SQL data types. For more on
data type mapping between SQL and C or C++ data types refer to:
– “Supported SQL data types in C and C++ routines” on page 131
• Include routine logic. Routine logic can consist of any code supported in the C or C++ programming
language. It can also include the execution of embedded SQL statements which is implemented in
the same way as for embedded SQL applications.
For more on executing SQL statements in embedded SQL see:
Results
To invoke your C or C++ routine, see “Invoking routines” on page 205.
Procedure
There are two ways to build C and C++ routines:
• Using database sample build scripts (Linux and UNIX) or build batch files (Windows)
• Entering database and C or C++ compiler commands from the Db2 Command Window
The database sample build scripts and batch files are designed for building database sample routines
(procedures and user-defined functions) and user created routines for a particular operating system that
uses the default supported compilers.
There is a separate set of database sample build scripts and batch files for C and C++. In general, it is
easier to build embedded SQL routines with the build scripts or batch files, which can easily be modified
Procedure
To build a source code file that contains one or more routine code implementations:
1. Open the Db2 command window.
2. Copy your source code file into the same directory as the bldrtn script file.
3. If the routines will be created in the sample database, enter the build script name followed by the
name of the source code file without the .sqc or .sqC file extension:
bldrtn file-name
If the routines will be created in another database, enter the build script name, the source code file
name without any file extension, and the database name:
The bldrtn script precompiles, compiles, and links the source code and produces a shared library.
The script then copies the shared library to the function directory on the database server.
4. If this is not the first time that the source code is built, stop and restart the database instance to
ensure that the new version of the shared library is used by the database. You can restart the database
instance by entering the db2stop command followed by the db2start command.
Once you have successfully built the routine shared library and deployed it to the function directory on
the database server, you should complete the steps associated with the task of creating C and C++
routines. After routine creation is completed you will be able to invoke your routines.
Building C and C++ routine code from the Db2 command window
You can build C and C++ routines from the command line. The procedure to build C and C++ routines
include compilation and linking of the source code, followed by deploying the routine library. If you have
any embedded SQL statements present in the source code, you must first run the precompiler before you
can proceed with the C or C++ routine compilation. You must also bind the resulting bind file that is
generated by the precompiler.
Procedure
To build a source code file that contains one or more embedded SQL statements:
1. Open the Db2 command window.
2. Navigate to the directory that contains your source code file.
3. Establish a connection with the database in which the routines are created.
4. Precompile the source code file.
5. Bind the package that was generated to the database.
6. Compile the source code file.
7. Link the source code file to generate a shared library. The linking process requires the use of compiler
link options that references the database include directory.
8. Copy the shared library to the database function directory on the database server.
9. If you are not building the source code file for the first time, you must stop and restart the database
manager to ensure that the new version of the shared library is used by the database manager. You
can issue the db2stop command followed by the db2start command to restart the database
manager.
Results
Once you successfully built and deployed the routine library, you can register the new routine in the
database by running the CREATE statement. The routine must be registered before you can call the new
routine.
Example
The following example builds an embedded SQL C++ source code file that is named myfile.sqC, which
contains a routine implementation. The routine is compiled with IBM C and C++ compiler on the AIX
operating system.
1. Open the Db2 command window.
4. Precompile the source code file with the PREPARE or PREP command.
The precompiler displays an output to indicate whether there were any errors. The precompile step
generates a bind file that is named myfile.bnd, which can be used to generate a package in the next
step.
5. Bind the package that was generated to the database with the BIND command.
The bind utility displays an output to indicate whether there were any errors.
6. Compile the source code file and specify any compiler options that you need to specify. You must
include the database include directory.
The compiler displays an output to indicate whether there are any errors. This step generates an
export file named myfile.exp.
7. Link the compiled object to generate a shared library.
The linker displays an output to indicate whether there are any errors. This step generates a shared
library file name myfile.
8. Copy the shared library to the database function directory on the database server.
rm -f ~HOME/sqllib/function/myfile
cp myfile $HOME/sqllib/function/myfile
This step ensures that the routine library is in the default directory where the database manager looks
for routine libraries.
9. Stop and restart the database manager.
db2stop
db2start
The LD_LIBRARY_PATH operating system environment variable is ignored when a source code with
embedded SQL statements is built.
The database manager configuration parameter KEEPFENCED has the default value YES. When you are
developing new routines (stored procedures and UDFs), set the KEEPFENCED parameter to NO. Setting the
KEEPFENCED parameter to NO avoids routine process from persisting in the system and ensure that the
routine that is running on the system is the current version. You can change the KEEPFENCED parameter
back to YES when you deploy the final version of your routine.
For Java routines, the JDK_PATH parameter must be set.
Procedure
To change the database manager configuration parameter settings, enter the following command:
For example, enter the following command to set the KEEPFENCED parameter to NO:
To set the JDK_PATH parameter to the directory /home/db2inst/jdk17, enter the following command:
Results
To view the current settings in the database manager configuration parameters, enter the following
command:
Note: On Windows operating system, you need to enter the db2 update dbm cfg command in the Db2
command window.
COBOL procedures
COBOL procedures are to be written in a similar manner as COBOL subprograms.
Handling parameters in a COBOL procedure
Each parameter to be accepted or passed by a procedure must be declared in the LINKAGE SECTION.
For example, this code fragment comes from a procedure that accepts two IN parameters (one
CHAR(15) and one INT), and passes an OUT parameter (an INT):
LINKAGE SECTION.
01 IN-SPERSON PIC X(15).
01 IN-SQTY PIC S9(9) USAGE COMP-5.
01 OUT-SALESSUM PIC S9(9) USAGE COMP-5.
With these commands, the procedure returns correctly to the client application. This is especially
important when the procedure is called by a local COBOL client application.
When building a COBOL procedure, it is strongly recommended that you use the build script written for
your operating system and compiler. Build scripts for Micro Focus COBOL are found in the sqllib/
samples/cobol_mf directory. Build scripts for IBM COBOL are found in the sqllib/samples/cobol
directory.
The following is an example of a COBOL procedure that accepts two input parameters, and then returns
an output parameter and a result set:
IDENTIFICATION DIVISION.
PROGRAM-ID. "NEWSALE".
DATA DIVISION.
WORKING-STORAGE SECTION.
01 INSERT-STMT.
05 FILLER PIC X(24) VALUE "INSERT INTO SALES (SALES".
05 FILLER PIC X(24) VALUE "_PERSON,SALES) VALUES ('".
05 SPERSON PIC X(16).
05 FILLER PIC X(2) VALUE "',".
05 SQTY PIC S9(9).
05 FILLER PIC X(1) VALUE ")".
EXEC SQL BEGIN DECLARE SECTION END-EXEC.
01 INS-SMT-INF.
05 INS-STMT.
49 INS-LEN PIC S9(4) USAGE COMP.
49 INS-TEXT PIC X(100).
01 SALESSUM PIC S9(9) USAGE COMP-5.
EXEC SQL END DECLARE SECTION END-EXEC.
EXEC SQL INCLUDE SQLCA END-EXEC.
LINKAGE SECTION.
01 IN-SPERSON PIC X(15).
01 IN-SQTY PIC S9(9) USAGE COMP-5.
01 OUT-SALESSUM PIC S9(9) USAGE COMP-5.
The preceding statement assumes that the COBOL function exists in a library called NEWSALE.
Note: When registering a COBOL procedure on Windows operating systems, take the following precaution
when identifying a stored procedure body in the CREATE statement's EXTERNAL NAME clause. If you use
an absolute path id to identify the procedure body, you must append the .dll extension. For example:
Java routines
Java routines are external routines that have a Java programming language implementation.
Java routines are created in a database by executing a CREATE PROCEDURE or CREATE FUNCTION
statement. This statement must indicate that the routine is implemented in Java with the LANGUAGE
JAVA clause. It must also specify with the EXTERNAL clause, the Java class that implements it.
External procedures, functions, and methods can be created in Java.
Java routines can execute SQL statements.
The following terms are important in the context of Java routines:
CREATE statement
The SQL language CREATE statement used to create the routine in the database.
Routine-body source code
The source code file containing the Java routine implementation. The Java routine can access the
database using either JDBC or SQLJ application programming interfaces.
JDBC and SQLJ application programming interface support for Java routines
External routines that are developed in Java can use the following application programming interfaces
(APIs): JDBC and SQLJ.
The IBM Data Server Driver for JDBC and SQLJ product supports both the JDBC and SQLJ APIs and can
be used to develop external Java routines.
The procedures for implementing Java routines are the same regardless which API is used.
Procedure
1. Check the JDK_PATH parameter value with the get dbm cfg command from the Db2 command
window:
You might want to redirect the output to a file for easier viewing.
The JDK_PATH parameter value appears near the beginning of the output.
2. If you want to use a different JDK, install the JDK on the database server and note the JDK installation
path.
3. Update the JDK_PATH parameter value with the update dbm cfg command from the Db2 command
window, where path is the path where the new JDK is installed:
db2stop
db2start
What to do next
After you complete these steps, the JDK that is specified with the JDK_PATH parameter is used to run
Java routines. The CLASSPATH, PATH, and LIBPATH environment variables for JDK are set automatically
when the JDK_PATH parameter is set.
Procedure
• “Supported SQL data types in Java routines” on page 166
• “Parameters in Java routines” on page 169
• “Parameter style JAVA procedures” on page 169
• “Parameter style JAVA Java functions and methods” on page 170
• “Returning result sets from JDBC procedures” on page 179
• “Returning result sets from SQLJ procedures” on page 180
• “Restrictions on Java routines” on page 183
• “Table function execution model for Java” on page 60
What to do next
After having learned about the Java characteristics, you might want to refer to:
• “Creating Java routines from the command line” on page 185
Note:
1. Parameters of an SQL array data type are mapped to class com.ibm.db2.ARRAY.
2. LONG VARCHAR, LONG VARGRAPHIC, XML, REFERENCE, UDT and ARRAY are not supported for the
ARRAY data type.
class myClass
{
public static void myRoutine( short myInput )
{
DefaultContext ctx = DefaultContext.getDefaultContext();
#sql { some SQL statement };
In the following SQLJ example, each invocation of the routine creates its own unique ConnectionContext
object (and underlying JDBC connection), which avoids unexpected interference by concurrent threads.
#context MyContext;
class myClass
{
public static void myRoutine( short myInput )
{
MyContext ctx = new MyContext( "jdbc:default:connection", false );
#sql [ctx] { some SQL statement };
ctx.close();
}
}
method-name
Name of the method. During routine registration, this value is specified with the class name in the
EXTERNAL NAME clause of the CREATE PROCEDURE statement.
SQL-arguments
Corresponds to the list of input parameters in the CREATE PROCEDURE statement. OUT or INOUT
mode parameters are passed as single-element arrays. For each result set that is specified in the
DYNAMIC RESULT SETS clause of the CREATE PROCEDURE statement, a single-element array of type
ResultSet is appended to the parameter list.
result-set-array
Name of the array of ResultSet objects. For every result set declared in the DYNAMIC RESULT SETS
parameter of the CREATE PROCEDURE statement, a parameter of type ResultSet[] must be declared
in the Java method signature.
return;
}
The corresponding CREATE PROCEDURE statement for this stored procedure is as follows:
The preceding statement assumes that the method is in a class called stpclass, located in a JAR file
that has been cataloged to the database with the Jar ID myjar
Note:
1. PARAMETER STYLE JAVA routines use exceptions to pass error data back to the invoker. For complete
information, including the exception call stack, refer to administration notification log.
Other than this detail, there are no other special considerations for invoking PARAMETER STYLE JAVA
routines.
2. JNI calls are not supported in Java routines. However, it is possible to invoke C functionality from Java
routines by nesting an invocation of a C routine. This involves moving the desired C functionality into a
routine, registering it, and invoking it from within the Java routine.
return-type
The data type of the value to be returned by the scalar routine. Inside the routine, the return value is
passed back to the invoker through a return statement.
method-name
Name of the method. During routine registration, this value is specified with the class name in the
EXTERNAL NAME clause of the routine's CREATE statement.
SQL-arguments
Corresponds to the list of input parameters in the routine's CREATE statement.
public static double product( double in1, double in2 ) throws SQLException
{
return in1 * in2;
}
The corresponding CREATE FUNCTION statement for this scalar function is as follows:
The preceding statement assumes that the method is in a class called udfclass that is located in a JAR
file that has been installed to the database server with the Jar ID myjar. JAR files can be installed to a
database server using the INSTALL_JAR built-in procedure.
DB2GENERAL routines
PARAMETER STYLE DB2GENERAL routines are written in Java. Creating DB2GENERAL routines is very
similar to creating routines in other supported programming languages. After you created and registered
the routines, you can call them from programs in any language.
Typically, you can call JDBC APIs from your stored procedures, but you cannot call them from UDFs.
When developing routines in Java, it is strongly recommended that you register them using the
PARAMETER STYLE JAVA clause in the CREATE statement. PARAMETER STYLE DB2GENERAL is still
available to enable the implementation of the following features in Java routines:
• table functions
• scratchpads
• access to the DBINFO structure
• the ability to make a FINAL CALL (and a separate first call) to the function or method
If you have PARAMETER STYLE DB2GENERAL routines that do not use any of these features, it is
recommended that you port them to PARAMETER STYLE JAVA.
DB2GENERAL UDFs
You can create and use UDFs in Java just as you would in other languages. After you code the UDF, you
register it with the database. You can then refer to it in your applications.
In general, if you declare a UDF taking arguments of SQL types t1, t2, and t3, returning type t4, it is called
as a Java method with the expected Java signature:
Where:
• name is the Java method name
• T1 through T4 are the Java types that correspond to SQL types t1 through t4.
• a, b, and c are variable names for the input arguments.
• d is a variable name that represents the output argument.
For example, given a UDF called sample!test3 that returns INTEGER and takes arguments of type
CHAR(5), BLOB(10K), and DATE, the database manager expects the Java implementation of the UDF to
have the following signature:
import COM.ibm.db2.app.*;
public class sample extends UDF {
Java routines that implement table functions require more arguments. Beside the variables that
represent the input, an additional variable appears for each column in the resulting row. For example, a
table function can be declared as:
SQL NULL values are represented by Java variables that are not initialized. These variables have a value of
zero if they are primitive types, and Java null if they are object types, in accordance with Java rules. To tell
an SQL NULL apart from an ordinary zero, you can call the function isNull for any input argument:
{ ....
if (isNull(1)) { /* argument #1 was a SQL NULL */ }
else { /* not NULL */ }
}
In this example, the argument numbers start at one. The isNull() function, like the other functions that
follow, are inherited from the COM.ibm.db2.app.UDF class.
To return a result from a scalar or table UDF, use the set() method in the UDF, as follows:
{ ....
set(2, value);
}
Where '2' is the index of an output argument, and value is a literal or variable of a compatible type. The
argument number is the index in the argument list of the selected output. In the first example, the int
result variable has an index of 4; in the second, result1 through result3 have indices of 2 through 4.
Like C modules that are used in UDFs and stored procedures, you cannot use the Java standard I/O
streams (System.in, System.out, and System.err) in Java routines.
All the Java class files (or the JARs that contain the classes) that you use to implement a routine must
reside in the sqllib/function directory, or in a directory that is specified in the database manager's
CLASSPATH.
Typically, the database manager calls a UDF many times. The UDF can be called once for each row of an
input or result set in a query. If SCRATCHPAD is specified in the CREATE FUNCTION statement of the UDF,
the database manager recognizes that some "continuity" is needed between successive invocations of
the UDF, and therefore the implementing Java class is not instantiated for each call, but generally
speaking once per UDF reference per statement. Generally it is instantiated before the first call and used
thereafter, but can for table functions be instantiated more often. If, however, NO SCRATCHPAD is
specified for a UDF, either a scalar or table function, then a clean instance is instantiated for each call to
the UDF.
A scratchpad can be useful for saving information across calls to a UDF. While Java and OLE UDFs can
either use instance variables or set the scratchpad to achieve continuity between calls, C and C++ UDFs
must use the scratchpad. Java UDFs access the scratchpad with the getScratchPad() and
setScratchPad() methods available in COM.ibm.db2.app.UDF.
For Java table functions that use a scratchpad, control when you get a new scratchpad instance by using
the FINAL CALL or NO FINAL CALL option on the CREATE FUNCTION statement.
The ability to achieve continuity between calls to a UDF by means of a scratchpad is controlled by the
SCRATCHPAD and NO SCRATCHPAD option of CREATE FUNCTION, regardless of whether the database
scratchpad or instance variables are used.
For scalar functions, you use the same instance for the entire statement.
Note that every reference to a Java UDF in a query is treated independently, even if the same UDF is
referenced multiple times. This is the same as what happens for OLE, C, and C++ UDFs as well. At the end
of a query, if you specify the FINAL CALL option for a scalar function then the object's close() method is
Note:
1. The difference between REAL and DOUBLE in the SQLDA is the length value (4 or 8).
2. The Blob and Clob classes are provided in the COM.ibm.db2.app package. Their interfaces include
routines to generate an InputStream and OutputStream for reading from and writing to a Blob, and a
Reader and Writer for a Clob.
3. SQL DATE, TIME, and TIMESTAMP values use the ISO string encoding in Java, as they do for UDFs
coded in C.
You can only call inherited methods of the COM.ibm.db2.app.StoredProc interface in the context of
the currently executing stored procedure. For example, you cannot use operations on LOB arguments,
This constructor is called by the database before the stored procedure call.
This function tests whether an input argument with the given index is an SQL NULL.
This function sets the output argument with the given index to the given value. The index has to refer to a
valid output argument, the data type must match, and the value must have an acceptable length and
contents. Strings with Unicode characters must be representable in the database code page. Errors result
in an exception being thrown.
This function returns a JDBC object that represents the calling application's connection to the database.
It is analogous to the result of a null SQLConnect() call in a C stored procedure.
You can call methods of the COM.ibm.db2.app.UDF interface only in the context of the currently
executing UDF. For example, you cannot use operations on LOB arguments, result or status-setting calls,
and so on, after a UDF returns from execution. A Java exception is thrown if this rule is violated.
Argument-related calls use a column index to identify the column being set. The column indexes start at 1
for the first argument. Output arguments are numbered higher than the input arguments. For example, a
scalar UDF with three inputs uses index 4 for the output.
Any exception returned from the UDF is caught by the database and returned to the caller with SQLCODE
-4302, SQLSTATE 38501.
The following methods are associated with the COM.ibm.db2.app.UDF class:
This function is called by the database at the end of a UDF evaluation, if the UDF was created with the
FINAL CALL option. It is analogous to the final call for a C UDF. For table functions, close() is called
after the CLOSE call to the UDF method (if NO FINAL CALL is coded or defaulted), or after the FINAL call
(if FINAL CALL is coded). If a Java UDF class does not implement this function, a no-operation stub
handles and ignores this event.
Table function UDF methods use getCallType() to find out the call type for a particular call. It returns a
value as follows (symbolic defines are provided for these values in the COM.ibm.db2.app.UDF class
definition):
• -2 FIRST call
• -1 OPEN call
• 0 FETCH call
• 1 CLOSE call
• 2 FINAL call
This function tests whether an input argument with the given index is an SQL NULL.
This function tests whether an output argument with the given index must be set. This can be false for a
table UDF declared with DBINFO, if that column is not used by the UDF caller.
This function sets the output argument with the given index to the given value. The index must refer to a
valid output argument, the data type must match, and the value must have an acceptable length and
contents. Strings with Unicode characters must be representable in the database code page. Errors result
in an exception being thrown.
This function can be called from a UDF to set the SQLSTATE to be returned from this call. A table UDF can
call this function with "02000" to signal the end-of-table condition. If the string is not acceptable as an
SQLSTATE, an exception is thrown.
This function is like the setSQLstate function. It sets the SQL message result. If the string is not
acceptable (for example, longer than 70 characters), an exception is thrown.
This function returns a raw, unprocessed DBINFO structure for the executing UDF, as a byte array. You
must first declare it with the DBINFO option.
These functions return the value of the appropriate field from the DBINFO structure of the executing UDF.
This function returns the routine ID of the procedure which directly or indirectly called this routine. The
routine ID matches the ROUTINEID column in SYSCAT.ROUTINES which can be used to retrieve the name
of the calling procedure. If the executing routine is called from an application, getDBprocid() returns 0.
This function returns the SBCS, DBCS, and composite code page numbers for the database, from the
DBINFO structure. The returned integer array has the following numbers as its first three elements.
This function returns a copy of the scratchpad of the currently executing UDF. You must first declare the
UDF with the SCRATCHPAD option.
This function overwrites the scratchpad of the currently executing UDF with the contents of the given byte
array. You must first declare the UDF with the SCRATCHPAD option. The byte array must have the same
size as getScratchpad() returns.
The COM.ibm.db2.app.UDF class contains the following methods for facilitating the execution of Java
UDFs in a partitioned database environment:
This function returns a list of all the partitions included in the table function.
This function returns the partition number of the node on which the table function is currently executing.
The COM.ibm.db2.app.UDF class contains the following methods for getting information required to
create external generic table functions:
This function returns the data type of the specified output column.
This function creates a temporary Blob. It will be implemented using a LOCATOR if possible.
This function creates a temporary Clob. It will be implemented using a LOCATOR if possible.
This function returns a new InputStream to read the contents of the BLOB. Efficient seek/mark operations
are available on that object.
This function returns a new OutputStream to append bytes to the BLOB. Appended bytes become
immediately visible on all existing InputStream instances produced by this object's getInputStream()
call.
This function returns a new Reader to read the contents of the CLOB or DBCLOB. Efficient seek/mark
operations are available on that object.
This function returns a new Writer to append characters to this CLOB or DBCLOB. Appended characters
become immediately visible on all existing Reader instances produced by this object's GetReader() call.
When your stored procedure is created with the ARRAY data type parameters, your stored procedure can
accept or return a variable number of input data or return data of the same data type with a single
parameter.
For example, you can pass all the names of students in a class to a procedure without knowing the
number of students with a single parameter.
Procedure
To pass a parameter of type ARRAY:
1. The ARRAY data type must be already defined. To define an array type, the CREATE TYPE statement
must be executed.
2. The procedure definition must include a parameter of the defined type. The following CREATE
PROCEDURE statement example accepts a user-defined ARRAY data type IntArray:
Example
In the procedure definition, the array parameter is typed as java.sql.Array. Within the procedure, the
argument is mapped to a Java array using the getArray() method, as shown in the following example.
Notice the use of Integer rather than int (or other primitive types) for arrays.
Procedure
To return a result set from a JDBC procedure:
Connection con =
DriverManager.getConnection("jdbc:default:connection");
3. Prepare the SQL statement that will generate the result set (using a PreparedStatement object). In the
following example, the prepare is followed by the assignment of an input variable (called
inSalaryThreshold - refer to the previously shown function signature example) to the value of the
parameter marker in the query statement. A parameter marker is indicated with a "?" or a colon,
followed by a name (:name).
String query =
"SELECT name, job, CAST(salary AS DOUBLE) FROM staff " +
" WHERE salary > ? " +
" ORDER BY salary";
rs[0] = stmt.executeQuery();
What to do next
If you have not done so already, develop a client application or caller routine that will accept result sets
from your stored procedure.
Procedure
To return a result set from an SQLJ procedure:
1. Declare an iterator class to handle query data. For example:
2. For each result set that is to be returned, include a parameter of type ResultSet[] in the procedure
declaration. For example the following function signature accepts an array of ResultSet objects:
SpServerEmployees c1;
4. Assign the SQL statement that will generate the result set to an iterator. In the following example, a
host variable (called inSalaryThreshold -- refer to the previously shown function signature example) is
used in the query's WHERE clause:
rs[0] = c1.getResultSet();
What to do next
If you have not done so already, develop a client application or caller routine that will accept result sets
from your procedure.
Procedure
To accept procedure result sets from within a JDBC routine or application:
1. Open a database connection (using a Connection object):
Connection con =
DriverManager.getConnection("jdbc:db2:sample", userid, passwd);
2. Prepare the CALL statement that will invoke a procedure that returns result sets (using a
CallableStatement object). In the following example, a procedure named GET_HIGH_SALARIES is
invoked. The prepare is followed by the assignment of an input variable (called inSalaryThreshold -- a
numeric value to be passed to the procedure) to the value of the parameter marker in the previous
statement. A parameter marker is indicated with a "?" or by a colon followed by a name (:name).
stmt.execute();
4. Use the CallableStatement object's getResultSet() method to accept the first result set from the
procedure and fetch the rows from the result sets using the fetchAll() method:
ResultSet rs = stmt.getResultSet();
5. For multiple result sets, use the CallableStatement object's getNextResultSet() method to enable
the following result set to be read. Then repeat the process in the previous step, where the ResultSet
object accepts the current result set, and fetches the result set rows. For example:
while (callStmt.getMoreResults())
{
rs = callStmt.getResultSet()
rs.close();
Procedure
To accept procedure result sets from within an SQLJ routine or application:
1. Open a database connection (using a Connection object):
Connection con =
DriverManager.getConnection("jdbc:db2:sample", userid, passwd);
4. Invoke a procedure that returns result sets. In the following example, a procedure named
GET_HIGH_SALARIES is invoked, and is passed an input variable (called inSalaryThreshold):
5. Declare a ResultSet object, and use the ExecutionContext object's getNextResultSet() method to
accept result sets from the procedure. For multiple result sets, put the getNextResultSet() call in a
loop structure. Each result set returned by the procedure will spawn a loop iteration. Inside the loop,
you can fetch the result set rows method, and then close the result set object (with the ResultSet
object's close() method). For example:
ResultSet rs = null;
rs.close();
}
At each OPEN of the table function • Class constructor is called • UDF method is opened with OPEN
(means new scratchpad). UDF call.
method is called with OPEN call. • Method opens the scan for
• Constructor initializes class and whatever Web data it wants.
scratchpad variables. Method (Might be able to avoid reopen
connect to Web server, and opens after a CLOSE reposition,
the scan for Web data. depending on what is saved in the
scratchpad.)
At each FETCH for a new row of • UDF method is called with FETCH • UDF method is called with FETCH
table function data call. call.
• Method fetches and returns next • Method fetches and returns new
row of data, or EOT. row of data, or EOT.
At each CLOSE of the table function • UDF method is called with CLOSE • UDF method is called with CLOSE
call. close() method if it exists call.
for class. • Method might reposition to the
• Method closes its Web scan and top of the scan, or close the scan.
disconnects from the Web server. It can save any state in the
close() does not need to do scratchpad, which will persist.
anything.
After the last CLOSE of the table • No calls. • UDF method is called with FINAL
function call. close() method is called if
it exists for class.
• Method disconnects from the
Web server. close() method
does not need to do anything.
Note:
1. The term "UDF method" refers to the Java class method that implements the UDF. This is the method
identified in the EXTERNAL NAME clause of the CREATE FUNCTION statement.
Procedure
• Creating Java routines using IBM Data Studio
• Creating Java routines using Rational Application Developer
• “Creating Java routines from the command line” on page 185
Procedure
1. Code the routine logic in Java.
• A routine parameter signature must be implemented using one of the supported parameter styles. It
is strongly recommended that parameter style JAVA be used for all Java routines. For more on
parameter signatures and parameter implementations see:
– “Parameters in Java routines” on page 169
– “Parameter style JAVA procedures” on page 169
– “Parameter style JAVA Java functions and methods” on page 170
• Declare variables in the same manner as is done for Java database applications. Be careful to
correctly use data types that map to SQL data types.
For more on data type mapping between SQL and Java data types, see the following topics:
– "Data types that map to database data types in Java applications" in Developing Java Applications
• Include routine logic. Routine logic can consist of any code supported in the Java programming
language. It can also include the execution of SQL statements in the same manner as is done in Java
database applications.
For more on executing SQL statements in Java code see:
– "JDBC interfaces for executing SQL" in Developing Java Applications
– "SQL statement execution in SQLJ applications" in Developing Java Applications
• If the routine is a procedure and you might want to return a result set to the caller of the routine, you
do not require any parameters for the result set. For more on returning result sets from Java
routines:
– “Returning result sets from JDBC procedures” on page 179
– “Returning result sets from SQLJ procedures” on page 180
• Set a routine return value at the end of the routine.
2. Build your code to produce a Java class file or JAR file containing a collection of Java class files.
For information on how to build Java routine code, see:
• "Building JDBC routines" in Developing Java Applications
• "Building SQL routines" in Developing Java Applications
3. Copy the class file to the database server or install the JAR file to the database server.
For information on how to do this, see:
• “Deploying Java routine class files to database servers” on page 190
• “JAR file administration on the database server” on page 191
It is recommended that you store class files associated with database routines in the function
directory. To find out more about the function directory, see information related to the EXTERNAL
clause in one of the following statements: CREATE PROCEDURE or CREATE FUNCTION.
You can copy the library to another directory on the server if you wish, but to successfully invoke the
routine you must note the fully qualified path name of your library as you will require it for the next
step.
4. Execute either dynamically or statically the appropriate CREATE statement for the routine type:
CREATE PROCEDURE or CREATE FUNCTION.
• Specify the LANGUAGE clause with: JAVA
• Specify the PARAMETER STYLE clause with the name of the supported parameter style that was
implemented in the routine code. It is strongly recommended that PARAMETER STYLE JAVA be
What to do next
To invoke your Java routine, see “Invoking routines” on page 205.
Procedure
You can use one of the following tools to build Java routines:
• The graphical tool that is provided with IBM Data Studio
• The graphical tool that is provided within IBM IBM Data Studio
• The graphical tool that is provided within IBM Rational Application Developer
• The database sample build-scripts
• The Db2 command window
The sample build scripts and batch files for routines are designed for building sample routines
(procedures and user-defined functions) in a particular operating system with the default supported
development software.
There is a separate set of sample build scripts and batch files for Java routines that are created with JDBC
and SQLJ. It is easier to build Java routines with the graphical tools or the build scripts, which can be
modified as required. However, it is often helpful to know how to build routines from the Db2 command
window.
javac SpServer.java
javac UDFsrv.java
javac UDFsqlsv.java
Procedure
1. Build the stored procedure application with this command:
spcat
This script connects to the sample database, uncatalogs the routines if they were previously cataloged
by calling SpDrop.db2, then catalogs them by calling SpCreate.db2, and finally disconnects from
the database. You can also run the SpDrop.db2 and SpCreate.db2 scripts individually.
3. Stop and restart the database to allow the new class file to be recognized. If necessary, set the file
mode for the class file to read, so it is readable by the fenced user.
4. Compile and run the SpClient client application to access the stored procedure class.
You can build SpClient with the application build file, bldsqlj (Linux and UNIX), or bldsqlj.bat
(Windows).
db2set DB2INSTPROF
Deploying Java routine class files to database servers with dependent classes
When the Java routine class files have dependencies on classes that are not part of the standard Java or
database classes, repeat the steps that are identified in the previous section for each dependent class.
Alternatively, the database can be configured to search the directories in the CLASSPATH environment
variable in order to detect dependant classes. On Windows operating systems, the database manager
searches the specified directories in the CLASSPATH system environment variable. On UNIX and Linux
operating systems, the database manager searches the instance owner's CLASSPATH environment
variable if the text " CLASSPATH " is specified as part of the DB2ENVLIST environment variable. It is
strongly recommended that dependant classes be installed rather than relying on the CLASSPATH
environment variable.
Note: The privileges held by the authorization ID of the caller of sqlj.install_jar must include at least
one of the following:
• CREATEIN privilege for the implicitly or explicitly specified schema
• DBADM authority
Replace
Remove
sqlj.remove_jar( jar-id )
• jar-url: The URL containing the JAR file to be installed or replaced. The only URL scheme supported is
'file:'.
• jar-id: A unique string identifier, up to 128 bytes in length. It specifies the JAR identifier in the database
associated with the jar-url file.
• jar-locator: A BLOB locator input parameter that points to the JAR file that is to be installed in the Db2
catalog.
Note: When invoked from applications, the stored procedures sqlj.install_jar and sqlj.remove_jar have an
additional parameter. It is an integer value that dictates the use of the deployment descriptor in the
specified JAR file. At present, the deployment parameter is not supported, and any invocation specifying
a nonzero value will be rejected.
Subsequent SQL commands that use the bobsjar.jar file refer to it with the name MYJAR.
To replace MYJAR with a different JAR containing some updated classes:
Note: On Windows operating systems, the database stores JAR files in the path that is specified by the
DB2INSTPROF instance-specific registry setting. To make JAR files unique for an instance, you must
specify a unique value for DB2INSTPROF for that instance.
Note: On a partitioned database system, the command sqlj.install_jar() only installs the JAR file
on the node issuing the command. Run sqlj.replace_jar() on each node to copy the jar file.
To ensure that the database manager uses the new version of the Java routine, you must execute a built-
in procedure that loads the new version of the Java class into memory.
Procedure
To update Java routine classes:
1. Deploy the new Java class or JAR file to the database server.
2. Execute the following built-in procedure for fenced routines:
CALL SQLJ.REFRESH_CLASSES()
The CALL SQLJ.REFRESH_CLASSES() statement forces the database manager to load the new class
into memory upon the next commit or rollback operation.
The CALL SQLJ.REFRESH_CLASSES() statement does not affect the unfenced routines. For
unfenced routines, you must explicitly stop and restart the database manager in order for new
versions of Java routine classes to be loaded and used.
Note: On a partitioned database system, loading new classes requires you to issue the
sqlj.refresh_classes() command on all database partitions. This can be done with the db2_all
command. In order for this command to work, you need to connect to the database first, and use \"
around the call command. Otherwise a syntax error will appear. This is shown by this example:
Results
If you do not perform the steps listed previously, after you update Java routine classes, the database
manager will continue to use the previous versions of the classes.
Procedure
• Examples of Java (JDBC) procedures
• Examples of Java (JDBC) procedures with XML features
• Examples of Java (JDBC) functions
import java.sql.Array;
Procedure
You can use the following example as references when you are making your own Java procedures:
• “The Java external code file” on page 194
• “Example: Parameter style JAVA procedure with XML parameters” on page 195
using System;
import java.lang.*;
import java.io.*;
import java.sql.*;
import java.util.*;
import com.ibm.db2.jcc.DB2Xml;
The Java class file imports are indicated at the top of the file. The com.ibm.db2.jcc.DB2Xml import is
required if any of the procedures in the file contain parameters or variables of type XML is used.
It is important to note the name of the class file and JAR name that contains the procedure
implementation. These names are important because the EXTERNAL clause of the CREATE PROCEDURE
statement for each procedure must specify this information so that the database manager can locate the
class at run time.
//*************************************************************************
// Stored Procedure: XMLPROC1
//
// Purpose: Inserts XML data into XML column; queries and returns XML data
//
// Parameters:
//
// IN: inNum -- the sequence of XML data to be insert in xmldata table
// inXML -- XML data to be inserted
// OUT: out1XML -- XML data to be returned
// out2XML -- XML data to be returned
//
//*************************************************************************
stmt = con.prepareStatement(query);
stmt.setInt(1, inNum);
stmt.setString (2, xmlString );
stmt.executeUpdate();
stmt.close();
// Query and retrieve a single XML value from a table using SQL
query = "SELECT xdata from xmlDataTable WHERE num = ? " ;
stmt = con.prepareStatement(query);
stmt.setInt(1, inNum);
ResultSet rs = stmt.executeQuery();
rs.close() ;
stmt.close();
// Query and retrieve a single XML value from a table using XQuery
query = "XQUERY for $x in db2-fn:xmlcolumn(\"xmlDataTable.xdata\")/doc
where $x/make = \'Mazda\'
return <carInfo>{$x/make}{$x/model}</carInfo>";
stmt = con.createStatement();
rs = stmt.executeQuery( query );
if ( rs.next() )
{ out2Xml[0] = (DB2Xml) rs.getObject(1) ; }
rs.close();
stmt.close();
con.close();
return ;
}
The OLE automation objects must be creatable by an OLE automation controller out side of the database
and support late binding (also called IDispatch-based binding). OLE automation objects must be
registered in the Windows registry with a class identifier (CLSID), and optionally, an OLE programmatic ID
(progID) to identify the automation object. The progID can identify an in-process (.DLL) or local (.EXE) OLE
automation server, or a remote server through DCOM (Distributed COM).
Procedure
To register OLE automation routines:
• After you code an OLE automation object, you need to create the methods of the object as routines
using the CREATE statement. Creating OLE automation routines is very similar to registering C or C++
routines, but you must use the following options:
The calling conventions for OLE method implementations are identical to the conventions for routines
written in C or C++. An implementation of the previous method in the BASIC language looks like the
following (notice that in BASIC the parameters are by default defined as call by reference):
Data that is passed between the database and OLE automation routines is passed as call by reference.
The following types are not supported:
• SQL types such as BIGINT, DECIMAL, BINARY, VARBINARY, or LOCATORS
• OLE automation types such as Boolean or CURRENCY
Character and graphic data mapped to BSTR is converted from the database code page to the UCS-2
scheme. (UCS-2 is also known as Unicode, IBM code page 13488). Upon return, the data is converted
back to the database code page from UCS-2. These conversions occur regardless of the database code
page. If these code page conversion tables are not installed, you receive SQLCODE -332 (SQLSTATE
57017).
Table 13. Mapping of SQL and OLE data types to BASIC and C++ data types
SQL Type OLE Automation Type BASIC C++ Type
Type
SMALLINT short Integer short
INTEGER long Long long
REAL float Single float
OLE supports type libraries that describe the properties and methods of OLE automation objects. Exposed
objects, properties, and methods are described in the Object Description Language (ODL). The ODL
description of the previously shown C++ method is as follows:
You can use the ODL description to specify whether a parameter is an input ([in]), output ([out]), or
input/output ([in,out]) parameter. For an OLE automation routine, the routine input parameters and
input indicators are specified as [in] parameters, and routine output parameters and output indicators
as [out] parameters. For the routine trailing arguments, sqlstate is an [out] parameter, fname and
fspecname are [in] parameters, scratchpad is an [in,out] parameter, and calltype is an [in]
parameter.
OLE automation defines the BSTR data type to handle strings. BSTR is defined as a pointer to OLECHAR:
typedef OLECHAR *BSTR. For allocating and freeing BSTRs, OLE imposes the rule that the called
routine frees a BSTR passed in as a by-reference parameter before routine assigns the parameter a new
value. The same rule applies for one-dimensional byte arrays that are received by the called routine as
SAFEARRAY**. The following list contains OLE imposed rules on parameters:
• [in] parameters: The database manager allocates and frees [in] parameters.
• [out] parameters: The database manager passes in a pointer to NULL. The [out] parameter must be
allocated by the routine that is called and is freed by the database manager.
• [in,out] parameters: The database manager initially allocates [in,out] parameters. They can be
freed and reallocated by the routine that is called. As is true for [out] parameters, the database
manager frees the final returned parameter.
All other parameters are passed as pointers. The database manager allocates and manages the
referenced memory.
OLE automation provides a set of data manipulation functions for dealing with BSTRs and SAFEARRAYs.
The following C++ routine returns the first 5 characters of a CLOB input parameter:
An OLE automation server can be implemented as creatable single-use or creatable multi-use. When an
OLE automation server is implemented as creatable single-use, each client (that is, a FENCED process)
that connects with the CoGetClassObject function to an OLE automation object uses its own instance
of a class factory, and run a new copy of the OLE automation server. When an OLE automation server is
implemented as creatable multi-use, many clients connect to the same class factory. In an OLE
automation server that is implemented as creatable multi-use, each instantiation of a class factory is
supplied by an already running copy of the OLE server. If there are no copies of the OLE server running, a
copy is automatically started to supply the class object. The choice between single-use and multi-use
OLE automation servers is yours, when you implement your automation server. A single-use server can
provide better performance.
Procedure
To define an OLE DB table function with a single CREATE FUNCTION statement, you must:
• define the table that the OLE DB provider returns
• specify LANGUAGE OLEDB
• identify the OLE DB rowset and provide an OLE DB provider connection string in the EXTERNAL NAME
clause
OLE DB data sources expose their data in tabular form, called a rowset. A rowset is a set of rows, each
having a set of columns. The RETURNS TABLE clause includes only the columns relevant to the user. The
binding of table function columns to columns of a rowset at an OLE DB data source is based on column
names. If the OLE DB provider is case sensitive, place the column names in quotation marks; for example,
"UPPERcase".
'server!rowset'
or
'!rowset!connectstring'
where:
server
identifies a server registered with the CREATE SERVER statement
rowset
identifies a rowset, or table, exposed by the OLE DB provider; this value should be empty if the table
has an input parameter to pass through command text to the OLE DB provider.
connectstring
contains initialization properties needed to connect to an OLE DB provider. For the complete syntax
and semantics of the connection string, see the "Data Link API of the OLE DB Core Components" in
the Microsoft OLE DB 2.0 Programmer's Reference and Data Access SDK, Microsoft Press, 1998.
You can use a connection string in the EXTERNAL NAME clause of a CREATE FUNCTION statement, or
specify the CONNECTSTRING option in a CREATE SERVER statement.
For example, you can define an OLE DB table function and return a table from a Microsoft Access
database with the following CREATE FUNCTION and SELECT statements:
Instead of putting the connection string in the EXTERNAL NAME clause, you can create and use a server
name. For example, assuming you have defined the server Nwind, you could use the following CREATE
FUNCTION statement:
OLE DB table functions also allow you to specify one input parameter of any character string data type.
Use the input parameter to pass command text directly to the OLE DB provider. If you define an input
parameter, do not provide a rowset name in the EXTERNAL NAME clause. The database passes the
command text to the OLE DB provider for execution and the OLE DB provider returns a rowset to the
database. Column names and data types of the resulting rowset need to be compatible with the RETURNS
TABLE definition in the CREATE FUNCTION statement. You must ensure that you name the columns
properly, because binding of the column names of the rowset is based on matching column names.
The following example registers an OLE DB table function, which retrieves store information from a
Microsoft SQL Server 7.0 database. The connection string is provided in the EXTERNAL NAME clause. The
table function has an input parameter to pass through command text to the OLE DB provider, so the
rowset name is not specified in the EXTERNAL NAME clause. The query example passes in a SQL
command text that retrieves information about the top three stores from a SQL Server database.
For more information on constructing fully qualified names, refer to Microsoft OLE DB 2.0 Programmer's
Reference and Data Access SDK, Microsoft Press, 1998, and the documentation for your OLE DB provider.
Table 14. Mapping of the database data types to the OLE DB data types
Database Data Type OLE DB Data Type
SMALLINT DBTYPE_I2
Note: OLE DB data type conversion rules are defined in the Microsoft OLE DB 2.0 Programmer's Reference
and Data Access SDK, Microsoft Press, 1998. For example:
• To retrieve the OLE DB data type DBTYPE_CY, the data can get converted to OLE DB data type
DBTYPE_NUMERIC(19,4), which maps to the database data type DEC(19,4).
• To retrieve the OLE DB data type DBTYPE_I1, the data can get converted to OLE DB data type
DBTYPE_I2, which maps to the database data type SMALLINT.
• To retrieve the OLE DB data type DBTYPE_GUID, the data can get converted to OLE DB data type
DBTYPE_BYTES, which maps to the database data type CHAR(12) FOR BIT DATA.
Invoking routines
Once a routine has been developed and created in the database by issuing the CREATE statement, if the
appropriate routine privileges have been granted to the routine definer and routine invoker, the routine
can be invoked.
Each routine type serves a different purpose and is used in a different way. The prerequisites for invoking
routines is common, but the implementation of the invocation differs for each.
Procedure invocation
Procedures are invoked by executing the CALL statement with a reference to a procedure.
The CALL statement enables the procedure invocation, the passing of parameters to the procedure, and
the receiving of parameters returned from the procedure. Any accessible result sets returned from a
procedure can be processed once the procedure has successfully returned.
Procedures can be invoked from anywhere that the CALL statement is supported including:
• client applications
• External routines (procedure, UDF, or method)
• SQL routines (procedure, UDF, or method)
• Triggers (before triggers, after triggers, or instead of triggers)
• Dynamic compound statements
• Command line processor (CLP)
If you choose to invoke a procedure from a client application or from an external routine, the client
application or external routine can be written in a language other than that of the procedure. For example,
a client application written in C++ can use the CALL statement to invoke a procedure written in Java. This
provides programmers with great flexibility to program in their language of choice and to integrate code
pieces written in different languages.
In addition, the client application that invokes the procedure can be executed on a different operating
system than the one where the procedure resides. For example a client application running on a Windows
operating system can use the CALL statement to invoke a procedure residing on a Linux database server.
Depending on where a procedure is invoked from there might be some additional considerations.
Function invocation
Functions are intended to be referenced within SQL statements.
Built-in functions, sourced aggregate functions, and scalar user-defined can be referenced wherever an
expression is allowed within an SQL statement. For example within the select-list of a query or within the
VALUES clause of an INSERT statement. Table functions can only be referenced in the FROM clause. For
example in the FROM clause of a query or a data change statement.
Method invocation
Methods are similar to scalar functions except that they are used to give behavior to structured types.
Method invocation is the same as scalar user-defined function invocation, except that one of the
parameters to the method must be the structured type that the method operates on.
1. Definer performs the appropriate CREATE statement to register the routine. This registers the routine
in the database with its intended level of SQL access, establishes the routine signature, and also points
to the routine executable. The definer, if not also the package owner, needs to communicate with the
package owners and authors of the routine programs to be clear on where the routine libraries reside
so that this can be correctly specified in the EXTERNAL clause of the CREATE statement. By virtue of a
successful CREATE statement, the definer has EXECUTE WITH GRANT privilege on the routine,
however the definer does not yet have EXECUTE privilege on the packages of the routine.
However, you can also omit the schema-name., in which case, the database manager will attempt to
identify the stored procedure or UDF to which you are referring. For example:
The concept of SQL path is central to the resolution of unqualified references that occur when you do not
use the schema-name. The SQL path is an ordered list of schema names. It provides a set of schemas for
resolving unqualified references to stored procedures, UDFs, and types. In cases where a reference
matches a stored procedure, type, or UDF in more than one schema in the path, the order of the schemas
in the path is used to resolve this match. The SQL path is established by means of the FUNCPATH option
on the precompile and bind commands for static SQL. The SQL path is set by the SET PATH statement for
dynamic SQL. The SQL path has the following default value:
"SYSIBM","SYSFUN","SYSPROC", "ID"
This applies to both static and dynamic SQL, where ID represents the current statement authorization ID.
Routine names can be overloaded, which means that multiple routines, even in the same schema, can
have the same name. Multiple functions or methods with the same name can have the same number of
parameters, as long as the data types differ. This is not true for stored procedures, where multiple stored
procedures with the same name must have different numbers of parameters. Instances of different
routine types do not overload one-another, except for methods, which are able to overload functions. For
a method to overload a function, the method must be registered using the WITH FUNCTION ACCESS
clause.
A function, a stored procedure, and a method can have identical signatures and be in the same schema
without overloading each other. In the context of routines, signatures are the qualified routine name
concatenated with the defined data types of all the parameters in the order in which they are defined.
Methods are invoked against instances of their associated structured type. When a subtype is created,
among the attributes it inherits are the methods defined for the supertype. Hence, a supertype's methods
This is done by including both the FENCED clause and NOT THREADSAFE clause in the routine CREATE
statement when creating a new routine. For routines that have already been created in the 64-bit
instance, the ALTER FUNCTION or ALTER PROCEDURE statements can be used to modify the routine
definition. The first time such a 32- bit routine is invoked in a 64- environment, there will be a
performance degradation. Subsequent invocations of the 32-bit stored procedure will perform as well as
an equivalent 64-bit routine. Use of 32-bit routines in 64-bit database instances is discouraged.
To successfully invoke Java procedures in a 64-bit database instance on a 64-bit database server, a 64-
bit Java Virtual Machine (JVM) is required. 32-bit JVMs are not supported for running routines in 64-bit
database instances. As Java classes are platform independent, a Java class compiled with a 32-bit
software development kit can run successfully with a 64-bit JVM. Routine performance is not impacted by
doing this.
Procedure
To invoke existing 32-bit routines on a 64-bit server:
1. Copy the routine class or library to the database routines directory:
• Linux and UNIX: sqllib/function
References to procedures
Stored Procedures are invoked from the CALL statement where they are referenced by a qualified name
(schema and stored procedure name), followed by a list of arguments enclosed by parentheses. A stored
procedure can also be invoked without the schema name, resulting in a choice of possible stored
procedures in different schemas with the same number of parameters.
Each parameter passed to the stored procedure can be composed of a host variable, parameter marker,
expression, or NULL. The following are restrictions for stored procedure parameters:
• OUT and INOUT parameters must be host variables.
• NULLs cannot be passed to Java stored procedures unless the SQL data type maps to a Java class type.
• NULLs cannot be passed to PARAMETER STYLE GENERAL stored procedures.
The position of the arguments is important and must conform to the stored procedure definition for the
semantics to be correct. Both the position of the arguments and the stored procedure definition must
conform to the stored procedure body itself. The database manager does not attempt to shuffle
arguments to better match a stored procedure definition, and the database manager do not understand
the semantics of the individual stored procedure parameters.
Calling procedures
Once the activities required to create a procedure (also called a stored procedure) have been completed,
a procedure can be invoked by using the CALL statement. The CALL statement is an SQL statement that
enables the procedure invocation, the passing of parameters to the procedure, and the receiving of
parameters returned from the procedure.
The procedure must have been created in the database by executing the CREATE PROCEDURE statement.
For external procedures, the library or class file must exist in the location specified by the EXTERNAL
clause in the CREATE PROCEDURE statement.
The procedure invoker must have the privileges required to execute the CALL statement. The procedure
invoker in this case is the user ID executing the application, however special rules apply if the
DYNAMICRULES bind option is used for the application.
Procedure
Certain elements must be included in your application if you want that application to invoke a procedure.
In writing your application you must do the following:
1. Declare, allocate, and initialize storage for the optional data structures and host variables or
parameter markers required for the CALL statement.
To do this:
• Assign a host variable or parameter marker to be used for each parameter of the procedure.
• Initialize the host variables or parameter markers that correspond to IN or INOUT parameters.
2. Establish a database connection. Do this by executing an embedded SQL language CONNECT TO
statement, or by coding an implicit database connection.
3. Code the procedure invocation. After the database connection code, you can code the procedure
invocation. Do this by executing the SQL language CALL statement. Be sure to specify a host variable,
constant, or parameter marker for each IN, INOUT, OUT parameter that the procedure expects.
4. Add code to process the OUT and INOUT parameters, and result sets. This code must come after the
CALL statement execution.
5. Code a database COMMIT or ROLLBACK. Subsequent to the CALL statement and evaluation of output
parameter values or data returned by the procedure, you might want your application to commit or roll
back the transaction. This can be done by including a COMMIT or ROLLBACK statement. A procedure
can include a COMMIT or ROLLBACK statement, however it is recommended practice that transaction
management be done within the client application.
Note: Procedures invoked from an application that established a type 2 connection to the database,
cannot issue COMMIT or ROLLBACK statements.
6. Disconnect from the database.
7. Prepare, compile, link, and bind your application. If the application is for an external routine, issue the
CREATE statement to create the routine and locate your external code library in the appropriate
function path for your operating system so that the database manager can find it.
8. Run your application or invoke your external routine. The CALL statement that you embedded in your
application will be invoked.
Results
Note: You can code SQL statements and routine logic at any point between steps 2 and 5.
• The procedure must have been created in the database by executing the CREATE PROCEDURE
statement.
• For external procedures, the library or class files must be in the location specified by the EXTERNAL
clause of the CREATE PROCEDURE statement.
• The creator of a trigger that contains a CALL statement must have the privilege to execute the CALL
statement. At runtime when a trigger is activated it is the authorization of the creator of the trigger that
is checked for the privilege to execute the CALL statement. A user that executes a dynamic compound
statement that contains a CALL statement, must have the privilege to execute the CALL statement for
that procedure.
• To invoke a trigger, a user must have the privilege to execute the data change statement associated
with the trigger event. Similarly, to successfully invoke an SQL routine or dynamic compound statement
a user must have the EXECUTE privilege on the routine.
Restrictions
When invoking a procedure from within an SQL trigger, an SQL routine, or a dynamic compound statement
the following restrictions apply:
• In partitioned database environments procedures cannot be invoked from triggers or SQL UDFs.
• On symmetric multi-processor (SMP) machines, procedure calls from triggers are executed on a single
processor.
• A procedure that is to be called from a trigger must not contain a COMMIT statement or a ROLLBACK
statement that attempts to roll back the unit of work. The ROLLBACK TO SAVEPOINT statement is
supported within the procedure however the specified savepoint must be in the procedure.
• A rollback of a CALL statement from within a trigger will not roll back any external actions effected by
the procedures, such as writing to the file system.
• The procedure must not modify any federated table. This means that the procedure must not contain a
searched UPDATE of a nickname, a searched DELETE from a nickname or an INSERT to a nickname.
• Result sets specified for the procedure will not be accessible from inline SQL PL statements.
• If a cursor defined as WITH RETURN TO CLIENT is opened during the execution of a compiled trigger,
result sets from the cursor will be discarded.
BEFORE triggers can not be created if they contain a CALL statement that references a procedure created
with an access level of MODIFIES SQL DATA. The execution of a CREATE TRIGGER statement for such a
trigger will fail with error (SQLSTATE 42987). For more about SQL access levels in routines see:
• “SQL access levels in routines” on page 38
• “SQL statements that can be executed in routines and triggers” on page 33
Procedure
This procedure section explains how to create and invoke a trigger that contains a CALL statement. The
SQL required to call a procedure from a trigger is the same SQL required to call a procedure from an SQL
routine or dynamic compound statement.
1. Write a basic CREATE TRIGGER statement specifying the desired trigger attributes. See the CREATE
TRIGGER statement.
2. In the trigger action portion of the trigger you can declare SQL variables for any IN, INOUT, OUT
parameters that the procedure specifies. See the DECLARE statement. To see how to initialize or set
Results
Runtime errors might occur if the procedure attempts to read or write to a table that the trigger also reads
or writes to, an error might be raised if a read or write conflict is detected. The set of tables that the
trigger modifies, including the table for which the trigger was defined must be exclusive from the tables
modified by the procedure.
Issuing the following SQL statement will cause the trigger to fire and the procedure will be invoked.
Procedure
To call a stored procedure, first connect to the database:
where userid and password are the user ID and password of the instance where the sample database is
located.
To use the CALL statement, enter the stored procedure name plus any IN or INOUT parameter values and
a place-holder ('?') for each OUT parameter values.
The parameters for a stored procedure are defined in the CREATE PROCEDURE statement for the stored
procedure.
Note: CLP call statement truncates the output parameter values to 8k for blob, clob, dbclob, graphic,
vargraphic, and longvargraphic types.
Example
SQL procedure examples
Example 1.
In the whiles.db2 file, the CREATE PROCEDURE statement for the DEPT_MEDIAN procedure
signature is as follows:
The DEPT_MEDIAN procedure selects the STAFF table for the specified deptNumber value. You
can call the DEPT_MEDIAN procedure with the following CALL statement:
On Linux and UNIX operating systems, the parentheses have special meaning to the command
shell, so they must be preceded with a "\" character or surrounded with quotation marks, as
follows:
You do not use quotation marks if you are using the interactive mode of the command line
processor. The following results are returned from the DEPT_MEDIAN procedure:
Return Status = 0
Example 2.
The example 2 illustrates how to call a procedure with array parameters. The user-defined data
type phonenumbers is defined as follows:
SET i = 1;
SET j = 1;
SET numbers_out = NULL;
SET max = CARDINALITY(numbers_in);
To call the find_customers procedure, you can use the following CALL statement:
As shown in the CALL statement example, when a procedure has an input parameter of an array
data type, the input argument can be specified with an array constructor that contains a list of
literal values.
The following results are returned from the find_customers procedure:
Return Status = 0
The MAIN_EXAMPLE procedure selects the job value from the EMPLOYEE table. The C sample
program, spclient, that calls the stored procedure, uses 'DESIGNER' for the JOB value. :
Return Status = 0
References to functions
The position of the arguments is important and must conform to the function definition for the semantics
to be correct. Both the position of the arguments and the function definition must conform to the function
body.
Each reference to a function, whether it is a UDF, or a built-in function, contains the following syntax:
function_name ( )
,
expression
In the preceding syntax diagram, function_name can be either an unqualified or a qualified function
name. The arguments can number from 0 to 90 and are expressions. Examples of some components that
can compose expressions are the following:
• a column name, qualified or unqualified
• a constant
• a host variable
• a special register
• a parameter marker
The database manager does not attempt to shuffle arguments to better match a function definition, and
do not understand the semantics of the individual function parameters.
Use of column names in UDF argument expressions requires that the table references that contain the
columns have proper scope. For table functions referenced in a join and using any argument involving
columns from another table or table function, the referenced table or table function must precede the
table function containing the reference in the FROM clause.
You cannot use the following code to specify the parameter markers in the BLOOP function:
BLOOP(?)
Because the function selection logic does not know what data types the argument might turn out to be, it
cannot resolve the reference. You can use the CAST specification to provide a type for the parameter
marker. For example, INTEGER, and then the function selection logic can proceed:
BLOOP(CAST(? AS INTEGER))
AVG(FLOAT_COLUMN)
BLOOP(COLUMN1)
BLOOP(FLOAT_COLUMN + CAST(? AS INTEGER))
BLOOP(:hostvar :indicvar)
BRIAN.PARSE(CHAR_COLUMN CONCAT USER, 1, 0, 0, 1)
CTR()
FLOOR(FLOAT_COLUMN)
PABLO.BLOOP(A+B)
PABLO.BLOOP(:hostvar)
"search_schema"(CURRENT FUNCTION PATH, 'GENE')
SUBSTR(COLUMN2,8,3)
SYSFUN.FLOOR(AVG(EMP.SALARY))
SYSFUN.AVG(SYSFUN.FLOOR(EMP.SALARY))
SYSIBM.SUBSTR(COLUMN2,11,LENGTH(COLUMN3))
SQRT((SELECT SUM(length*length)
FROM triangles
WHERE id= 'J522'
AND legtype <> 'HYP'))
TABLE(PABLO.BLOOP(A+B)) AS Q
Function selection
For both qualified and unqualified function references, the function selection algorithm looks at all the
applicable functions, both built-in and user-defined, that have: the given name; the same number of
defined parameters as arguments in the function reference; and each parameter identical to or
promotable from the type of the corresponding argument.
Applicable functions are functions in the named schema for a qualified reference, or functions in the
schemas of the SQL path for an unqualified reference. The algorithm looks for an exact match, or failing
that, a best match among these functions. The SQL path is used, in the case of an unqualified reference
only, as the deciding factor if two identically good matches are found in different schemas.
Exception: If there is an unqualified reference to a function named RID, and the function is invoked with a
single argument that matches a table-reference in the FROM clause of the subselect, the schema is
SYSIBM and the built-in RID function is invoked.
You can nest function references, even references to the same function. This is generally true for built-in
functions as well as UDFs; however, there are some limitations when column functions are involved.
For example:
In this statement, if column1 is a DECIMAL or DOUBLE column, the inner BLOOP reference resolves to the
second BLOOP. Because this BLOOP returns an INTEGER, the outer BLOOP resolves to the first BLOOP.
Alternatively in this DML statement, if column1 is a SMALLINT or INTEGER column, the inner bloop
reference resolves to the first BLOOP. Because this BLOOP returns an INTEGER, the outer BLOOP also
resolves to the first BLOOP. In this case, you are seeing nested references to the same function.
By defining a function with the name of one of the SQL operators, you can actually invoke a UDF using infix
notation. For example, suppose you can attach some meaning to the "+" operator for values which have
distinct type BOAT. You can define the following UDF:
Note that you are not permitted to overload the built-in conditional operators such as >, =, LIKE, IN, and
so on, in this way.
Procedure
You must explicitly cast distinct type arguments that originate from host variables when they are used to
call an UDFs or a method that accepts distinct types parameters.
The explicit casting is required by the database, which uses strong typing and to avoid ambiguous results.
The following example contains the CREATE statement for the BOAT_COST UDF that accepts BOAT
distinct type, which is defined from a BLOB:
In the following fragment of a C language application, the host variable :ship holds the BLOB value that
is passed to the BOAT_COST function:
Both of the following statements correctly resolve to the BOAT_COST function because both cast
the :ship host variable to type BOAT:
If there are multiple BOAT distinct types in the database, or BOAT UDFs in other schema, you must
exercise care with your SQL path. Your results can otherwise be ambiguous.
When you pass a LOB value as an argument to a function, the entire LOB value is stored by the database
manager before the function is invoked, even if the source of the value is a LOB locator host variable. In
the following C language application example, either host variable :clob150K or :clob_locator1 is
valid as an argument for a function whose corresponding parameter is defined as CLOB(500K):
Both of the following invocations of the FINDSTRING function are valid in the program:
UDF parameters or results, which have one of the LOB types can be created with the AS LOCATOR
modifier. In this case, the entire LOB value is not materialized prior to invocation. Instead, a LOB
LOCATOR is passed to the UDF, which can then use SQL to manipulate the actual bytes of the LOB value.
• For built-in functions, SYSIBM must be in the CURRENT PATH special register. SYSIBM is in CURRENT
PATH by default.
• For user-defined scalar functions, the function must have been created in the database using either the
CREATE FUNCTION or CREATE METHOD statement.
• For external user-defined scalar functions, the library or class file associated with the function must be
in the location specified by the EXTERNAL clause of the CREATE FUNCTION or CREATE METHOD
statement.
• To invoke a user-defined function or method, a user must have EXECUTE privilege on the function or
method. If the function or method is to be used by all users, the EXECUTE privilege on the function or
method can be granted to PUBLIC. For more privilege related information see the specific CREATE
statement reference.
Procedure
To invoke a scalar UDF or method:
• Include a reference to it within an expression contained in an SQL statement where it is to process one
or more input values. Functions and methods can be invoked anywhere that an expression is valid.
Examples of where a scalar UDF or method can be referenced include the select-list of a query or in a
VALUES clause.
Example
For example, suppose that you have created a user-defined scalar function called TOTAL_SAL that adds
the base salary and bonus together for each employee row in the EMPLOYEE table.
Procedure
To invoke a user-defined table function, reference the function in the FROM clause of an SQL statement
where it is to process a set of input values. The reference to the table function must be preceded by the
TABLE clause and be contained in brackets.
For example, the following CREATE FUNCTION statement defines a table function that returns the
employees in a specified department number.
Index 223
CHAR FOR BIT DATA data type 173 D
CLASSPATH environment variable 190
CLOB data type data types
Java 166, 173 ARRAY 179
OLE DB table functions 204 conversion
user-defined functions (UDFs) 135 OLE automation types 197
COBOL language Java 166
development software for external procedures 163 DATE data type
stored procedures 161 Java 166, 173
COM.ibm.db2.app.Blob class OLE DB table functions 204
data types 173 DB2GENERAL parameter style 65
overview 178 DB2GENERAL routines
COM.ibm.db2.app.Clob class Java classes
data types 173 COM.ibm.db2.app.Blob 178
overview 178 COM.ibm.db2.app.Clob 178
COM.ibm.db2.app.Lob class COM.ibm.db2.app.Lob 178
overview 178 COM.ibm.db2.app.StoredProc 174
COM.ibm.db2.app.StoredProc class COM.ibm.db2.app.UDF 175
overview 174 overview 174
COM.ibm.db2.app.UDF overview 171
DB2GENERAL UDFs 171 stored procedures 174
COM.ibm.db2.app.UDF class user-defined functions 171, 175
overview 175 DB2SQL parameter style for external routines 65
command line processor (CLP) DBCLOB data type
routine creation 32 Java 166
common language runtime (CLR) OLE DB table functions 204
functions routines 173
examples 98, 114 user-defined functions (UDFs) 135
procedures debugging
examples 91, 102 PL/SQL 54
returning result sets 80 routines
routines .NET CLR 88
.NET 88 SQL PL 54
building 85, 87 DECIMAL data type
creating 83 conversion
Dbinfo structure usage 78 Java 166
designing 76 DB2GENERAL routines 173
developing 75, 76 OLE DB table functions 204
errors 89 user-defined functions (UDFs) 135
examples 91 distinct types
overview 75 passing to routines 219
parameters 78 DOUBLE data type
restrictions 82 Java 166
scratchpad 78 user-defined functions (UDFs) 135
security 81
SQL data types 76
XML support 108
E
XQuery support 108 errors
contexts .NET CLR routines 89
setting in multithreaded applications EXECUTE privilege
SQLJ routines 168 routines 50, 207
CREATE FUNCTION statement external procedures
CAST FROM clause 135 COBOL 163
LANGUAGE OLE clause 196 external routines
OLE automation routines 196 APIs 19
PARAMETER STYLE clause 125, 170 class files
RETURNS clause 135 backing up 74
CREATE METHOD statement deploying 72
PARAMETER STYLE clause 170 modifying 74
CREATE PROCEDURE statement restoring 74
PARAMETER STYLE clause 122, 169 security 73
PROGRAM TYPE clause 130 creating 69
examples 193
features 55
Index 225
JDBC (continued) OLE automation (continued)
routines (continued) class identifier (CLSID) 196
examples (summary) 193 controllers 196
stored procedures 179 methods 196
XML OLECHAR data type 199
example 193 programmatic identifier (progID) 196
jdk_path configuration parameter routines
application development 161 defining 196
routines designing 196
building (UNIX) 164 invoking methods 197
running (UNIX) 164 object instances 197
SCRATCHPAD option 197
servers 196
K string data types 199
keepfenced configuration parameter OLE DB
updating 161 data types
mappings to database data types 204
fully qualified rowset names 204
L routines 143
table user-defined functions 202
large objects (LOBs)
overloading routine names 209
passing to routines 219
libraries
shared P
rebuilding routines 160
Linux parameter styles
SQLJ routines 189 overview 65
LONG VARCHAR data type PARAMETER STYLE DB2GENERAL 169
C/C++ 135 PARAMETER STYLE JAVA 169
Java 166, 173 parameters
OLE DB table functions 204 C/C++ routines 121
LONG VARCHAR FOR BIT DATA data type performance
Java 173 external routines 74
LONG VARGRAPHIC data type routines
Java 166, 173 benefits 2
OLE DB table functions 204 external 74
parameter to UDF 135 recommendations 41
PL/SQL
debugging 54
M portability
routines 40
methods
procedures
comparison with other functional types of routines 13
ADMIN_CMD
distinct types as parameters 219
overview 28
external 55
C/C++ result sets 155
Java PARAMETER STYLE clause 170
calling
overview 13
applications 212
MODIFIES SQL DATA clause
external routines 212
SQL access levels in SQL routines 38
overview 211
multi-threaded applications
SQL routines 213
SQLJ routines 168
triggers 213
common language runtime (CLR) examples 91
N functions comparison 13
Java
NUMERIC data type PARAMETER STYLE JAVA clause 169
Java 166, 173 methods comparison 13
OLE DB table functions 204 overview 8
NUMERIC parameter 135 parameters
PARAMETER STYLE JAVA clause 169
O PARAMETER STYLE SQL clause 122
references 211
object instances result sets
OLE automation routines 197 .NET CLR 80, 91
OLE automation
BSTR data type 199
Index 227
routines (continued) routines (continued)
external (continued) procedures (continued)
security 73 writing 71
SQL statement support 33 read conflicts 53
updating Java routines 192 rebuilding shared libraries 160
XML data type support 67 recursive 210
forbidden statements 67 restrictions 67
function path 209 scalar UDFs 56
functional types 8 scratchpad structure 64
functions security 48, 49
determining type to use 16 sourced 25, 28
overview 9 SQL
row 11 comparison to other types 25, 28
scalar 11 overview 18
table 12 SQL statement support 33, 39
graphic host variables 153 types
implementations comparison of functional types 13
built-in 18 comparison of routine implementations 28
comparison 28 determining functional type to use 16
overview 17 functional 8
sourced 18 overview 3
SQL 18 SQL statements supported 33
interoperability 40 user-defined
invoking comparison to built-in 6
32-bit routines on 64-bit database servers 210 creating 1, 5
from other routines 40 details 5
functions 205 determining which implementation to use 28
methods 205 overview 3, 5, 17, 29
prerequisites 205 pre-installed 5
procedures 205 when to use 7
security 48 writing 71
Java uses 28, 29
creating 184, 185 WCHARTYPE precompiler option 153
designing 166 write conflicts 53
JAR files 191 writing 71
JDBC 164, 187 row functions
overview 163 details 11
restrictions 183 row sets
SQLJ 164 OLE DB
XML data type support 67 fully qualified names 204
libraries 72
methods
details 13
S
when to use 16 scalar functions
writing 71 external 56
names 209 overview 11
nested 210 processing model 57
NOT FENCED scratchpads
security 48, 49 32-bit operating systems 64
OLE automation 196 64-bit operating systems 64
overloading 209 external functions 61
overview 2, 3 Java UDFs 171
passing arguments 143 methods 61
passing distinct types 219 OLE automation routines 197
passing LOBs 219 preserving state 61
performance 41 SDKs
portability UNIX 164
between 32-bit and 64-bit platforms 64 security
overview 40 PL/SQL debugging 54
procedures routines 48, 49
details 8 SQL PL debugging 54
read conflicts 53 shared libraries
when to use 16 rebuilding routines 160
write conflicts 53 short data type
Index 229
V
VARCHAR data type
Java (DB2GENERAL) routines 173
Java routines 166
OLE DB table functions 204
VARCHAR FOR BIT DATA data type
C/C++ user-defined functions 135
Java (DB2GENERAL) routines 173
VARGRAPHIC data type
C/C++ user-defined functions 135
Java (DB2GENERAL) routines 173
Java routines 166
OLE DB table functions 204
W
wchar_t data type
C/C++ routines 135
WCHARTYPE precompiler option
graphic host variables 153
Windows
SQLJ routines 189
X
XML data type
external routines 67