User Defined Functions
User Defined Functions
iv SAP Sybase IQ
Contents
User-Defined Functions v
Contents
get ......................................................................203
Column Data (a_v4_extfn_column_data) ...................204
Column List (a_v4_extfn_column_list) ........................206
Column Order (a_v4_extfn_order_el) .........................206
Column Subset (a_v4_extfn_col_subset_of_input) ....207
Describe API ...............................................................208
*describe_column_get .......................................209
*describe_column_set .......................................225
*describe_parameter_get ..................................242
*describe_parameter_set ...................................261
*describe_udf_get ..............................................277
*describe_udf_set ..............................................279
Describe Column Type
(a_v4_extfn_describe_col_type) ............................281
Describe Parameter Type
(a_v4_extfn_describe_parm_type) .........................282
Describe Return (a_v4_extfn_describe_return) ..........284
Describe UDF Type (a_v4_extfn_describe_udf_type)
................................................................................286
Execution State (a_v4_extfn_state) ............................287
External Function (a_v4_extfn_proc) ..........................288
_start_extfn ........................................................289
_finish_extfn .......................................................289
_evaluate_extfn ..................................................290
_describe_extfn .................................................290
_enter_state_extfn .............................................291
_leave_state_extfn .............................................291
External Procedure Context
(a_v4_extfn_proc_context) .....................................292
get_value ...........................................................294
get_value_is_constant .......................................296
set_value ...........................................................297
get_is_cancelled ................................................298
set_error ............................................................298
log_message .....................................................299
vi SAP Sybase IQ
Contents
convert_value ....................................................300
get_option .......................................................... 301
alloc ................................................................... 301
free .....................................................................302
open_result_set ................................................. 303
close_result_set .................................................304
get_blob ............................................................. 304
set_cannot_be_distributed .................................305
License Information (a_v4_extfn_license_info) ...........305
Optimizer Estimate (a_v4_extfn_estimate) ................. 306
Order By List (a_v4_extfn_orderby_list) ..................... 307
Partition By Column Number
(a_v4_extfn_partitionby_col_num) ......................... 307
Row (a_v4_extfn_row) ................................................ 309
Row Block (a_v4_extfn_row_block) ............................ 309
Table (a_v4_extfn_table) .............................................310
Table Context (a_v4_extfn_table_context) ..................311
fetch_into ........................................................... 313
fetch_block .........................................................316
rewind ................................................................ 318
get_blob ............................................................. 318
Table Functions (a_v4_extfn_table_func) .................. 319
_open_extfn ....................................................... 321
_fetch_into_extfn ................................................322
_fetch_block_extfn ............................................. 322
_rewind_extfn .....................................................323
_close_extfn .......................................................324
API Troubleshooting for a_v4_extfn ................................325
Generic describe_column Errors ................................ 325
Generic describe_udf Errors .......................................326
Generic describe_parameter Errors ........................... 326
Missing UDF Returns an Error ................................... 327
External Environment for UDFs ........................................329
Executing UDFs from an External Environment ......... 330
External Environment Restrictions ............................. 331
Audience
The User-Defined Functions guide is intended for SQL analysts, C developers, C++
developers, and Java developers who want to extend the functionality of SAP® Sybase® IQ.
As a developer, use the tasks, concepts, and API reference material to program non-SQL
external user-defined functions.
As a SQL analyst, use this guide to develop SQL queries that reference non-SQL external
user-defined functions.
User-Defined Functions 1
Audience
2 SAP Sybase IQ
Understanding User-Defined Functions
User-Defined Functions 3
Understanding User-Defined Functions
4 SAP Sybase IQ
Understanding User-Defined Functions
User-Defined Functions 5
Understanding User-Defined Functions
6 SAP Sybase IQ
Understanding User-Defined Functions
User-Defined Functions 7
Understanding User-Defined Functions
Practices to Avoid
Learn good practices for creating user-defined functions.
• Do not write ambiguous code, or constructs that can unexpectedly loop forever, without
providing a mechanism for the user to cancel the UDF invocation (see the function
'get_is_cancelled()'.
• Do not perform complex, or memory-intensive operations that are repeated every
invocation. When a UDF call is made against a table that contains many thousands of rows,
efficient execution becomes paramount. Allocate blocks of memory for a thousand to
several thousand rows at a time, rather than on a row-by-row basis.
• Do not open a database connection, or perform database operations from within a UDF. All
parameters and data required for UDF execution must be passed as parameters to the UDF.
• Do not use reserved words when naming UDFs.
Note: Use source control software for C++ UDFs and Java UDFs to track changes to:
• The source code (.java files/.cpp files)
• The class/jar/dll/so files that may be deployed to the database or mentioned in the
UDF stored procedure definition.
• The Syntax for the UDF stored procedure definition itself.
• Deployment instructions, 3rd party library versions and special deployment notes such as
security specifics.
See also
• get_is_cancelled on page 298
8 SAP Sybase IQ
Understanding User-Defined Functions
SQL reserved words. For a list of SQL reserved words in SAP Sybase IQ see Reserved Words
in Reference: Building Blocks, Tables, and Procedures.
Although UDF names (as other identifiers) may also contain reserved words, spaces,
characters other than those listed above, and may start with a non-alphabetic character, this is
not recommended. If UDF names have any of these characteristics, you must enclose them in
quotes or square brackets, which makes it more difficult to use them.
The UDFs reside in the same name space as other SQL functions and stored procedures. To
avoid conflicts with existing stored procedures and functions, preface UDFs with a unique
short (2-letter to 5-letter) acronym and underscore. Choose UDF names that do not conflict
with other SQL functions or stored procedures already defined in the local environment.
These are some of the prefixes that are already in use:
• debugger_tutorial – a stored procedure delivered with the native SAP Sybase IQ
installation.
• ManageContacts – a stored procedure delivered with the SAP Sybase IQ demo database.
• Show – stored procedures used to display data from the SAP Sybase IQ demo database.
• sp_Detect_MPX_DDL_conflicts – a stored procedure delivered with the native SAP
Sybase IQ installation.
• sp_iqevbegintxn – a stored procedure delivered with the native SAP Sybase IQ
installation.
• sp_iqmpx – functions and stored procedures provided by SAP Sybase IQ to assist in
multiplex administration.
• ts_ – optional financial time series and forecasting functions.
User-Defined Functions 9
Understanding User-Defined Functions
10 SAP Sybase IQ
Understanding User-Defined Functions
User-Defined Functions 11
Understanding User-Defined Functions
12 SAP Sybase IQ
Understanding User-Defined Functions
User-Defined Functions 13
Understanding User-Defined Functions
See also
• Blob (a_v4_extfn_blob) on page 199
• Blob Input Stream (a_v4_extfn_blob_istream) on page 203
• convert_value on page 300
• Table (a_v4_extfn_table) on page 310
14 SAP Sybase IQ
Building UDFs
Building UDFs
Design, build, and test UDFs.
Sample Code
Sample UDF source code is delivered with the product. The newest version of the sample code
is always delivered with the most current version of SAP Sybase IQ.
On UNIX platforms, the sample UDF code is in $SYBASE/IQ-16.0/samples/udf
(where $SYBASE is the installation root).
On Windows platforms, the sample UDF code is in C:\Documents and Settings
\All Users\SybaseIQ\samples\udf.
The sample UDF code documented in the User-Defined Functions guide may not be the latest
version as delivered with the SAP Sybase IQ product. Last-minute changes to the sample UDF
source code are documented in the Release Bulletin for your operating system platform.
User-Defined Functions 15
Building UDFs
This definition informs the server of which interface style is being used, and therefore how to
access the UDFs defined in this dynamically linkable library. For high-performance UDFs,
only new interface styles EXTFN_V3_API and EXTFN_V4_API are supported.
Prerequisites
Install SAP Sybase IQ server version 16.0.
Task
If you have existing scalar or aggregate UDFs developed for SAP Sybase IQ server versions
15.1, 15.2, or 15.3, those UDFs use the V3 API interface style and reference the
extfnapiv3.h header file. Modify your legacy C or C++ external library files to reference
the extfnapiv4.h header file.
Existing v3 scalar and aggregate functions continue to work as designed. However, to take
advantage of scalar and aggregate distribution in PlexQ, you must upgrade the header file and
library version to v4. You need not change the name of the typedefs for your scalar or
aggregate function.
1. Open the C or C++ external library file defining the scalar or aggregate user-defined
function.
2. Locate all instances of #include 'extfnapiv3.h' and change to #include
'extfnapiv4.h'.
3. Set the dynamic library interface to EXTFN_V4_API.
4. Rebuild.
Next
Partners must ensure the library exports extfn_get_license_info as an entry point.
See also
• External Function Prototypes on page 93
• License Information (a_v4_extfn_license_info) on page 305
• Defining an Aggregate UDF on page 53
• Defining a Scalar UDF on page 37
• Developing a Table UDF on page 103
• Developing a TPF on page 136
16 SAP Sybase IQ
Building UDFs
Implementation
A v4 library can define this optional entry point:
size_t extfn_get_library_version( uint8 *buff, size_t len );
Description
Library versioning methods are at the library level, and do not have the a_v4 prefix in their
method name.
If the v4 library defines the optional entry point, the server allows query distribution to other
nodes. The entry point populates the supplied buffer with the library version string (a C-style
character string containing only ASCII characters, terminated with \0) and returns the actual
size of the populated version string, which is constrained to a maximum of 256 bytes.
If an entry point is not defined, the server does not distribute the UDF to the other nodes in the
multiplex.
See also
• Library Version Compatibility (extfn_check_version_compatibility) on page 17
• Setting the Dynamic Library Interface on page 15
Implementation
A v4 library can define this optional entry point:
a_bool extfn_check_version_compatibility( uint8 *buff, size_t
len );
Description
Library versioning methods are at the library level, and do not have the a_v4 prefix in their
method name.
User-Defined Functions 17
Building UDFs
This optional entry point accepts a buffer containing the version string and the version string
length. It returns whether or not the library version on the target node is compatible with the
version string parameter. The library developer defines the compatibility criteria.
See also
• Library Version (extfn_get_library_version) on page 17
• Setting the Dynamic Library Interface on page 15
Data Type
an_extfn_license_info
Implementation
(_entry an_extfn_get_license_info) ( an_extfn_license_info
**license_info );
Parameters
license_info is an output parameter that returns the license information as received from the
library. You define the license information in the a_v4_extfn_license_info
structure.
18 SAP Sybase IQ
Building UDFs
Description
Design partners must specify the SAP-supplied license key in the
a_v4_extfn_license_info structure, and must ensure that the library exports
extfn_get_license_info as an entry point.
User-Defined Functions 19
Building UDFs
the library adhere to. The sample source file my_main.cxx contains this function; you
can use it without modification.
2. A UDF dynamically linkable library must also contain object code for at least one UDF
function. A UDF dynamically linkable library may optionally contain multiple UDFs.
3. Link together the object code for each UDF as well as the extfn_use_new_api() to form a
single library.
For example, to build the library "libudfex:"
• Compile each source file to produce an object file:
my_main.cxx
my_bit_or.cxx
my_bit_xor.cxx
my_interpolate.cxx
my_plus.cxx
my_plus_counter.cxx
my_sum.cxx
my_byte_length.cxx
my_md5.cxx
my_toupper.cxx
tpf_agg.cxx
tpf_blob.cxx
tpf_dt.cxx
tpf_filt.cxx
tpf_oby.cxx
tpf_pby.cxx
tpf_rg_1.cxx
tpf_rg_2.cxx
udf_blob.cxx
udf_main.cxx
udf_rg_1.cxx
udf_rg_2.cxx
udf_rg_3.cxx
udf_utils.cxx
• Link together each object produced into a single library.
After the dynamically linkable library has been compiled and linked:
• Update the CREATE FUNCTION ... EXTERNAL NAME or CREATE PROCEDURE ...
EXTERNAL NAME to include an explicit path name for the UDF library.
4. Run iqdir16/samples/udf/build.bat on Windows. Run iqdir16/
samples/udf/build.sh on UNIX.
1. Navigate to %ALLUSERSPROFILE%\samples\udf.
2. Run build.bat:
20 SAP Sybase IQ
Building UDFs
Parameter Description
-clean Deletes the object and the build directory
-v3 Builds sample scalar and aggregate UDFs with
the v3 API
-v4 (Default) Builds sample table UDFs and TPFs
with the v4 API
1. Navigate to $IQDIR15/samples/udf.
2. Run build.sh:
Parameter Description
-clean Deletes the object and the build directory
-v3 Builds sample scalar and aggregate UDFs with
the v3 API
-v4 (Default) Builds sample table UDFs and TPFs
with the v4 API
AIX Switches
Use the following compile and link switches when building shared libraries on AIX.
Note: To compile on AIX 6.1 systems, the minimum level of the xlC compiler is 10.0.
compile switches
-q64 -qarch=ppc64 -qtbtable=full -qsrcmsg -qalign=natural -
qnoansialias
-qmaxmem=-1 -qenum=int -qhalt=e -qflag=w -qthreaded -
qxflags=NLOOPING
-qtmplinst=none -qthreaded
link switches
-brtl -G -lg -lpthreads_compat -lpthreads -lm_r -ldl -bnolibpath -
v
User-Defined Functions 21
Building UDFs
HP-UX Switches
Use the following compile and link switches when building shared libraries on HP-UX.
link switches
-b -Wl,+s
Linux Switches
Use the following compile and link switches when building shared libraries on Linux.
Note: When compiling C++ applications for building shared libraries on Linux, adding the
-O2 and -Wall switches to the list of compile UDF switches decreases computation time.
link switches
-ldl -lnsl -lm -lpthread -shared -Wl,-Bsymbolic -Wl,-shared
Note: You can use gcc on Linux as well. While linking with gcc, link in the C++ run time
library by adding -lstdc++ to the link switches.
Examples
• Example 1
g++ -c my_interpolate.cxx -fPIC -fsigned-char -fno-exceptions -
pthread
-fno-omit-frame-pointer -Wno-deprecated -Wno-ctor-dtor-
privacy
-I${IQDIR16}/sdk/include/
• Example 2
g++ -c my_main.cxx -fPIC -fsigned-char -fno-exceptions -pthread
-fno-omit-frame-pointer -Wno-deprecated -Wno-ctor-dtor-
22 SAP Sybase IQ
Building UDFs
privacy
-I${IQDIR16}/sdk/include/
• Example 3
ld -G my_main.o my_interpolate.o -ldl -lnsl -lm -lpthread -shared
-o my_udf_library.so
link switches
-qmkshrobj -ldl -lg -qthreaded -lnsl -lm
Solaris Switches
Use the following compile and link switches when building shared libraries on Solaris.
link switches
-z defs -G -ldl -lnsl -lsocket -ladm -lposix4 -lCrun -lCstd -lc -lm
-lefi
-liostream -lkstat
link switches
-z defs -G -ldl -lnsl -lsocket -ladm -lposix4 -lCrun -lCstd -lc -lm
-lefi
-liostream -lkstat -m64
User-Defined Functions 23
Building UDFs
Windows Switches
Use the following compile and link switches when building shared libraries on Windows.
Example
Environment setup
set VCBASE=c:\dev\vc9
set MSSDK=C:\dev\mssdk6.0a
set IQINSTALLDIR=C:\Sybase\IQ
set OBJ_DIR=%IQINSTALLDIR%\IQ-16_0\samples\udf\objs
set SRC_DIR=%IQINSTALLDIR%\IQ-16_0\samples\udf\src
call %VCBASE%\VC\bin\vcvars32.bat
• Example 1
%VCBASE%\VC\bin\amd64\cl -c -nologo -DNDEBUG -DWINNT -D_USRDLL
-D_WINDLL -D_WIN64 -DWIN64 -
D_WIN32_WINNT=_WIN32_WINNT_WINXP
-DWINVER=_WIN32_WINNT_WINXP -D_MBCS -GS -W3 -Zi -favor:AMD64
-DSYB_LP64 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -
DHMSWNT
-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
-DPOINTERS_ARE_64BITS -DLONG_IS_64BITS -
D_RWSTD_NO_EXCEPTIONS
-I"%VCBASE%\VC\include" -I"%MSSDK%\include "-I"%MSSDK%\Lib
\AMD64"
-I"%VCBASE%\VC\lib\amd64" -DMSDCXX -DINT64_WORKAROUND
-DSUPPORTS_UDAF -Od -Zi -MD -I"%IQINSTALLDIR%\IQ-16_0\sdk
\include"
-Fo"%OBJ_DIR%\my_interpolate.o" %SRC_DIR%\my_interpolate.cxx
• Example 2
%VCBASE%\VC\bin\amd64\cl -c -nologo -DNDEBUG -DWINNT -D_USRDLL
-D_WINDLL -D_WIN64 -DWIN64 -
D_WIN32_WINNT=_WIN32_WINNT_WINXP
-DWINVER=_WIN32_WINNT_WINXP -D_MBCS -GS -W3 -Zi -favor:AMD64
-DSYB_LP64 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -
DHMSWNT
-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
-DPOINTERS_ARE_64BITS -DLONG_IS_64BITS -
24 SAP Sybase IQ
Building UDFs
D_RWSTD_NO_EXCEPTIONS
-I"%VCBASE%\VC\include" -I"%MSSDK%\include "-I"%MSSDK%\Lib
\AMD64"
-I"%VCBASE%\VC\lib\amd64" -DMSDCXX -DINT64_WORKAROUND
-DSUPPORTS_UDAF -Od -Zi -MD -I"%IQINSTALLDIR%\IQ-16_0\sdk
\include"
-Fo"%OBJ_DIR%\my_main.o" %SRC_DIR%\my_main.cxx
• Example 3
%VCBASE%\VC\bin\amd64\link /LIBPATH:%VCBASE%\VC\lib\amd64
/LIBPATH:%MSSDK%\lib\bin64 kernel32.lib -manifest -DLL -
nologo
-MAP:"%OBJ_DIR%\libudfex.map_deco" /OUT:"%OBJ_DIR%
\libudfex.dll"
"%OBJ_DIR%\my_interpolate.o" "%OBJ_DIR%\my_main.o" /DLL
-EXPORT:extfn_use_new_api -EXPORT:my_interpolate
• Example 4
%MSSDK%\bin\mt -nologo -manifest "%OBJ_DIR%
\libudfex.dll.manifest"
-outputresource:"%OBJ_DIR%\libudfex.dll;2"
User-Defined Functions 25
Building UDFs
Administrators can enable v3 and v4 UDFs for any server by specifying this in the server
startup command or in the configuration file:
-sf -inmemory_external_procedure
Administrators can disable v3 and v4 UDFs for any server by specifying this in the server
startup command or in the configuration file:
-sf inmemory_external_procedure
26 SAP Sybase IQ
Building UDFs
In UNIX, use
call sa_external_library_unload('/abc/def/library.so')
Note: The library path is required in the SQL function declaration only if the library is not
already located within a directory in the library load path.
Allowed Values
0, 1, 2
Default Value
0
Scope
Can be set as public, temporary, or user.
Description
When set to 0, the default, external UDFs are evaluated in a manner that optimizes the
performance of statements using UDFs.
When set to 1, external UDFs are evaluated to validate the information passed back and forth
to each UDF. This setting is intended for scalar and aggregate UDFs.
When set to 2, external UDFs are evaluated to not only validate the information passed back
and forth to the UDF, but also to log, in the iqmsg file, every call to the functions provided by
the UDFs and every callback from those functions back into the server. This setting is intended
for all C or C++ external UDFs. Memory tracing is turned on for table UDFs and TPFs.
User-Defined Functions 27
Building UDFs
The Windows output messages are slightly different from the output messages generated on
UNIX platforms.
Each platform will have a debugger and each will have their own command line syntax.
SAP Sybase IQ source code is not required. The msvs debugger will recognize when the
user-defined functions source is executed and break at the set breakpoints. When control
returns from the user-defined functions to the server, you will only see machine code.
28 SAP Sybase IQ
Building UDFs
2. Revoke the execute privilege from users, and drop the SQL functions and stored
procedures which reference external UDF code modules
3. Unload the library from the SAP Sybase IQ server, using the call
sa_external_library_unload command (shutting down the IQ server also automatically
unloads the library).
4. Perform the desired maintenance on the external library files (copy, move, update, delete).
5. Edit SQL function and stored procedure definitions in the registration scripts to reflect
external library locations, if the libraries were moved.
6. Grant the execute privilege to users, and run registration scripts to re-create the SQL
functions and stored procedures which reference external UDF code modules.
7. Invoke a SQL function or stored procedure that references the external UDF code to ensure
the SAP Sybase IQ server can dynamically load the external library.
Prerequisites
At least one of these conditions:
• You created the table.
• You have been granted privileges on the table with the ADMIN OPTION.
• You have been granted the EXECUTE ANY PROCEDURE system privilege.
• You have been granted LOAD and TRUNCATE object privileges.
• You have been granted the MANAGE ANY OBJECT PRIVILEGE system privilege. If the
LOAD or TRUNCATE object privilege is granted using the WITH GRANT OPTION clause,
the grantee can then grant the object privilege to other users, but is limited to those tables
specified in the original GRANT statement. Under this scenario, the grantee does not need
the MANAGE ANY OBJECT PRIVILEGE system privilege.
Task
Procedures execute with the privileges of their owner. Any procedure that updates information
on a table executes successfully only if the owner of the procedure has UPDATE privileges on
the table.
As long as the procedure owner has the proper privileges, the procedure executes successfully
when called by any user assigned privilege to execute it, whether or not he or she has privileges
on the underlying table. You can use procedures to allow users to carry out well-defined
activities on a table, without having any general privileges on the table.
To grant the EXECUTE privilege, enter:
GRANT EXECUTE ON procedure_name
TO usreID
User-Defined Functions 29
Building UDFs
To remove a table UDF or TPF named fullname from the database, enter:
DROP PROCEDURE fullname
30 SAP Sybase IQ
Scalar and Aggregate UDFs
User-Defined Functions 31
Scalar and Aggregate UDFs
1. Declare the UDF to the server by using the CREATE FUNCTION or CREATE AGGREGATE
FUNCTION statements. Write and execute these statements as commands, or use Sybase
Control Center.
The external C/C++ form of the CREATE FUNCTION statement requires the CREATE
EXTERNAL REFERENCE system privilege. Therefore, standard users do not have the
authority to declare any UDFs of this type.
2. Write the UDF library identification function on page 15.
3. Define the UDF as a set of C or C++ functions. See Defining a scalar UDF on page 37 or
Defining an aggregate UDF on page 53.
4. Implement the function entry points in C/C++.
5. Compile the UDF functions and the library identification functions on page 19.
6. Link the compiled file into a dynamically linkable library.
Any reference to a UDF in a SQL statement first, if necessary, links the dynamically linkable
library. The calling patterns on page 82 are then called.
Because these high-performance external C/C++ user-defined functions involve the loading
of non-server library code into the process space of the server, there are potential risks to data
integrity, data security, and server robustness from poorly or maliciously written functions. To
manage these risks, each SAP Sybase IQ server can explicitly enable or disable this
functionality on page 25.
32 SAP Sybase IQ
Scalar and Aggregate UDFs
parameter:
param-name data-type [ DEFAULT value ]
routine-characteristics:
[NOT] DETERMINISTIC
| { IGNORE | RESPECT } NULL VALUES
| SQL SECURITY { INVOKER | DEFINER }
To minimize potential security concerns, use a fully qualified path name to a secure directory
for the library name portion of the EXTERNAL NAME clause.
SQL Security
Defines whether the function is executed as the INVOKER, (the user who is calling the
function), or as the DEFINER (the user who owns the function). The default is DEFINER.
User-Defined Functions 33
Scalar and Aggregate UDFs
SQL SECURITY INVOKER uses additional memory, because each user that calls the procedure
requires annotation. Additionally, name resolution is performed on both the user name and the
INVOKER. Qualify all object names (tables, procedures, and so on) with their appropriate
owner.
External Name
A function using the EXTERNAL NAME clause is a wrapper around a call to a function in an
external library. A function using EXTERNAL NAME can have no other clauses following the
RETURNS clause. The library name may include the file extension, which is typically .dll
on Windows and .so on UNIX. In the absence of the extension, the software appends the
platform-specific default file extension for libraries.
You can start the server with a library load path that includes the location of the UDF library.
On UNIX variants, modify the LD_LIBRARY_PATH in the start_iq startup script.
While LD_LIBRARY_PATH is universal to all UNIX variants, SHLIB_PATH is preferred on
HP, and LIB_PATH is preferred on AIX.
On UNIX platforms, the external name specification can contain a fully qualified name, in
which case the LD_LIBRARY_PATH is not used. On the Windows platform, a fully qualified
name cannot be used and the library search path is defined by the PATH environment variable.
Note: Scalar user-defined functions and user-defined aggregate functions are not supported in
updatable cursors.
See also
• Defining a Scalar UDF on page 37
This declaration says that my_plus is a simple scalar UDF residing in my_shared_lib with a
descriptor routine named describe_my_plus. Since the behavior of a UDF may require more
than one actual C/C++ entry point for its implementation, this set of entry points is not directly
part of the CREATE FUNCTION syntax. Instead, the CREATE FUNCTION statement
EXTERNAL NAME clause identifies a descriptor function for this UDF. A descriptor
function, when invoked, returns a descriptor structure that is defined in detail in the next
34 SAP Sybase IQ
Scalar and Aggregate UDFs
section. That descriptor structure contains the required and optional function pointers that
embody the implementation of this UDF.
This declaration says that my_plus accepts two INT arguments and returns an INT result
value. If the function is invoked with an argument that is not an INT, and if the argument can be
implicitly converted into an INT, the conversion happens before the function is called. If this
function is invoked with an argument that cannot be implicitly converted into an INT, a
conversion error is generated.
Further, the declaration states that this function is deterministic. A deterministic function
always returns the identical result value when supplied the same input values. This means the
result cannot depend on any external information beyond the supplied argument values, or on
any side effects from previous invocations. By default, functions are assumed to be
deterministic, so the results are the same if this characteristic is omitted from the CREATE
statement.
The last piece of the above declaration is the IGNORE NULL VALUES characteristic. Nearly
all built-in scalar functions return a NULL result value if any of the input arguments are
NULL. The IGNORE NULL VALUES states that the my_plus function follows that
convention, and therefore this UDF routine is not actually invoked when either of its input
values are NULL. Since RESPECT NULL VALUES is the default for functions, this
characteristic must be specified in the declaration for this UDF to get the performance
benefits. All functions that may return a non-NULL result given a NULL input value must use
the default RESPECT NULL VALUES characteristic.
In the following example query, my_plus appears in the SELECT list along with the
equivalent arithmetic expression:
SELECT my_plus(t.x, t.y) AS x_plus_y_one, (t.x + t.y)AS x_plus_y_two
FROM t
WHERE t.z = 2
In the following example, my_plus is used in several different places and different ways within
the same query:
SELECT my_plus(t.x, t.y), count(*)
FROM t
WHERE t.z = 2
AND my_plus(t.x, 5) > 10
AND my_plus(t.y, 5) > 10
GROUP BY my_plus(t.x, t.y)
User-Defined Functions 35
Scalar and Aggregate UDFs
integer usage counter. If the input argument value is NULL, the result is the current value of
the usage counter.
my_plus_counter declaration
Assuming that my_plus_counter also resides within the dynamically linkable library
my_shared_lib, the declaration for this example is:
CREATE FUNCTION my_plus_counter (IN arg1 INT DEFAULT 0)
RETURNS INT
NOT DETERMINISTIC
RESPECT NULL VALUES
EXTERNAL NAME 'describe_my_plus_counter@my_shared_lib'
The RESPECT NULL VALUES characteristic means that this function is called even if the
input argument value is NULL. This is necessary because the semantics of my_plus_counter
includes:
• Internally keeping a usage count that increments even if the argument is NULL.
• A non-null value result when passed a NULL argument.
Because RESPECT NULL VALUES is the default, the results are the same if this clause is
omitted from the declaration.
SAP Sybase IQ restricts the usage of all nondeterministic functions. They are allowed only
within the SELECT list of the top-level query block or in the SET clause of an UPDATE
statement. They cannot be used within subqueries, or within a WHERE, ON, GROUP BY, or
HAVING clause. This restriction applies to nondeterministic UDFs as well as to the
nondeterministic built-in functions like GETUID and NUMBER.
The last detail in the above declaration is the DEFAULT qualifier on the input parameter. The
qualifier tells the server that this function can be called with no arguments, and that when this
happens the server automatically supplies a zero for the missing argument. If a DEFAULT
value is specified, it must be implicitly convertible into the data type of that argument.
In the following example, the first SELECT list item adds the running counter to the value of
t.x for each row. The second and third SELECT list items each return the same value for each
row as the NUMBER function.
SELECT my_plus_counter(t.x),
my_plus_counter(0),
my_plus_counter(),
NUMBER()
FROM t
36 SAP Sybase IQ
Scalar and Aggregate UDFs
This declaration says that my_byte_length is a simple scalar UDF residing in my_shared_lib
with a descriptor routine named describe_my_byte_length. Since the behavior of a UDF may
require more than one actual C/C++ entry point for its implementation, this set of entry points
is not directly part of the CREATE FUNCTION syntax. Instead, the CREATE FUNCTION
statement EXTERNAL NAME clause identifies a descriptor function for this UDF. A descriptor
function, when invoked, returns a descriptor structure. That descriptor structure contains the
required and optional function pointers that embody the implementation of this UDF.
This declaration also says that my_byte_length accepts one LONG BINARY argument and
returns an UNSIGNED INT result value.
Note: Large object data support requires a separately licensed SAP Sybase IQ option.
The declaration states that this function is deterministic, which always returns the identical
result value when supplied the same input values. This means the result cannot depend on any
external information beyond the supplied argument values, or on any side effects from
previous invocations. By default, functions are assumed to be deterministic, so the results are
the same if this characteristic is omitted from the CREATE statement.
The last piece of this declaration is the IGNORE NULL VALUES characteristic. Nearly all
built-in scalar functions return a NULL result value if any of the input arguments are NULL.
The IGNORE NULL VALUES states that the my_byte_length function follows that
convention, and therefore this UDF routine is not actually invoked when either of its input
values is NULL. Since RESPECT NULL VALUES is the default for functions, this
characteristic must be specified in the declaration for this UDF to get the performance
benefits. All functions that may return a non-NULL result given a NULL input value must use
the default RESPECT NULL VALUES characteristic.
This example query with my_byte_length in the SELECT list returns a column with one row
for each row in exTable, with an INT representing the size of the binary file:
SELECT my_byte_length(exLOBColumn)
FROM exTable
User-Defined Functions 37
Scalar and Aggregate UDFs
• a pointer to a data structure that allows access to the argument values and to the result
value through the supplied callbacks.
• a_v3_extfn_scalar – an instance of the scalar UDF descriptor structure that contains a
pointer to the evaluation function.
• Descriptor function – returns a pointer to the scalar UDF descriptor structure.
These parts are optional:
• _start_extfn – an initialization function generally invoked once per SQL usage. If
supplied, you must also place a pointer to this function into the scalar UDF descriptor
structure. All initialization functions take one argument, a pointer to the scalar UDF
context structure that is unique to each usage of a UDF. The context structure passed is the
same one that is passed to the evaluation routine.
• _finish_extfn – a shutdown function generally invoked once per SQL usage. If supplied, a
pointer to this function must also be placed into the scalar UDF descriptor structure. All
shutdown functions take one argument, a pointer to the scalar UDF context structure that is
unique to each usage of a UDF. The context structure passed is the same one that is passed
to the evaluation routine.
See also
• Declaring a Scalar UDF on page 33
} a_v3_extfn_scalar;
There should always be a single instance of a_v3_extfn_scalar for each defined scalar UDF. If
the optional initialization function is not supplied, the corresponding value in the descriptor
38 SAP Sybase IQ
Scalar and Aggregate UDFs
structure should be the null pointer. Similarly, if the shutdown function is not supplied, the
corresponding value in the descriptor structure should be the null pointer.
The initialization function is called at least once before any calls to the evaluation routine, and
the shutdown function is called at least once after the last evaluation call. The initialization and
shutdown functions are normally called only once per usage.
User-Defined Functions 39
Scalar and Aggregate UDFs
void * _for_server_internal_use;
} a_v3_extfn_scalar_context;
Note: The get_piece callback is valid in v3 and v4 scalar and aggregate UDFs. For v4 table
UDFs and TPFs, use the Blob (a_v4_extfn_blob) and Blob Input Stream
(a_v4_extfn_blob_istream) structures instead.
The _user_data field within the scalar UDF context structure can be populated with data the
UDF requires. Usually, it is filled in with a heap allocated structure by the _start_extfn
function, and deallocated by the _finish_extfn function.
The rest of the scalar UDF context structure is filled with the set of callback functions,
supplied by the engine, for use within each of the user's UDF functions. Most of these callback
functions return a success status through a short result value; a true return indicates success.
Well-written UDF implementations should never cause a failure status, but during
development (and possibly in all debug builds of a given UDF library), check that the return
status values from the callbacks. Failures can come from coding errors within the UDF
implementation, such as asking for more arguments than the UDF is defined to take.
The common set of arguments used by most of the callbacks includes:
• arg_handle – A pointer received by all forms of the evaluation methods, through which the
values for input arguments passed to the UDF are available, and through which the UDF
result value can be set.
• arg_num – An integer indicating which input argument is being accessed. Input arguments
are numbered left to right in ascending order starting at one.
• cntxt – A pointer to the context structure that the server passes to all UDF entry points.
• value – A pointer to an instance of the an_extfn_value structure that is used to either get an
input argument value from the server or to set the result value of the function. The
an_extfn_value structure has this form:
typedef struct an_extfn_value {
void * data;
a_SQL_uint32 piece_len;
union {
a_SQL_uint32 total_len;
a_SQL_uint32 remain_len;
} len;
a_SQL_data_type type;
} an_extfn_value;
40 SAP Sybase IQ
Scalar and Aggregate UDFs
See also
• Blob (a_v4_extfn_blob) on page 199
• Blob Input Stream (a_v4_extfn_blob_istream) on page 203
User-Defined Functions 41
Scalar and Aggregate UDFs
a_v3_extfn_scalar *my_plus()
{
return &my_plus_descriptor;
}
42 SAP Sybase IQ
Scalar and Aggregate UDFs
User-Defined Functions 43
Scalar and Aggregate UDFs
}
}
outval.type = DT_INT;
outval.piece_len = sizeof(a_sql_int32);
result = arg1 + cptr->_counter;
outval.data = &result;
cntxt->set_value( arg_handle, &outval, 0 );
}
a_v3_extfn_scalar *my_plus_counter()
{
return &my_plus_counter_descriptor;
}
44 SAP Sybase IQ
Scalar and Aggregate UDFs
an_extfn_value arg;
an_extfn_value outval;
a_sql_uint64 total_len;
fetchedLength += arg.piece_len;
User-Defined Functions 45
Scalar and Aggregate UDFs
//if this fails, the function did not get the full data from the
cell
assert(fetchedLength == total_len);
outval.type = DT_UNSINT;
outval.piece_len = 4;
outval.data = &fetchedLength;
cntxt->set_value(arg_handle, &outval, 0);
}
a_v3_extfn_scalar *my_byte_length()
{
return &my_byte_length_descriptor;
}
See also
• Example: my_byte_length Definition on page 45
46 SAP Sybase IQ
Scalar and Aggregate UDFs
An aggregate function can produce either a single result, or a set of results. The number of data
points in the output result set may not necessarily match the number of data points in the input
set. Multiple-output aggregate UDFs must use a temporary output file to hold the results.
parameter:
param-name data-type [ DEFAULT value ]
aggregate-routine-characteristics:
DUPLICATE { SENSITIVE | INSENSITIVE }
-- is the server allowed to eliminate DISTINCT
| SQL SECURITY {INVOKER | DEFINER}
| OVER restrict
| ORDER order-restrict
| WINDOW FRAME
{ { ALLOWED | REQUIRED }
[ window-frame-constraints ... ]
| NOT ALLOWED }
| ON EMPTY INPUT RETURNS { NULL | VALUE }
-- Call or skip function on NULL inputs
window-frame-constraints:
VALUES { [ NOT ] ALLOWED }
| CURRENT ROW { REQUIRED | ALLOWED }
| [ UNBOUNDED ] { PRECEDING | FOLLOWING } restrict
order-restrict:
{ NOT ALLOWED | SENSITIVE | INSENSITIVE | REQUIRED
User-Defined Functions 47
Scalar and Aggregate UDFs
The handling of the return data type, arguments, data types, and default values are identical to
that in the scalar UDF definition.
If an aggregate UDF can be used as a simple aggregate, then it can potentially be used with the
DISTINCT qualifier. The DUPLICATE clause in the aggregate UDF declaration determines:
• Whether duplicate values can be considered for elimination before the aggregate UDF is
called because the results are sensitive to duplicates (such as for the built-in
“COUNT(DISTINCT T.A)”) or,
• Whether the results are insensitive to the presence of duplicates (such as for
“MAX(DISTINCT T.A)”).
The DUPLICATE INSENSITIVE option allows the optimizer to consider removing the
duplicates without affecting the result, giving the optimizer the choice on how to execute the
query. Write the aggregate UDF to expect duplicates. If duplicate elimination is required, the
server performs it before starting the set of _next_value_extfn calls.
Most of the remaining clauses that are not part of the scalar UDF syntax allow you to specify
the usages for this function. By default, an aggregate UDF is assumed to be usable as both a
simple aggregate and as an OLAP-style aggregate with any kind of window frame.
For an aggregate UDF to be used only as a simple aggregate function, declare it using:
OVER NOT ALLOWED
Any attempt to then use this aggregate as an OLAP-style aggregate generates an error.
For aggregate UDFs that allow or require an OVER clause, the UDF definer can specify
restrictions on the presence of the ORDER BY clause within the OVER clause by specifying
“ORDER” followed by the restriction type. Window-ordering restriction types:
• REQUIRED – ORDER BY must be specified and cannot be eliminated.
• SENSITIVE – ORDER BY may or may not be specified, but cannot be eliminated when
specified.
• INSENSITIVE – ORDER BY may or may not be specified, but the server can do ordering
elimination for efficiency.
• NOT ALLOWED – ORDER BY cannot be specified.
Declare an aggregate UDF that makes sense only as an OLAP-style aggregate over an entire
set or partition that has been ordered, like the built-in RANK, with:
OVER REQUIRED
ORDER REQUIRED
WINDOW FRAME NOT ALLOWED
Declare an aggregate UDF that makes sense only as an OLAP-style aggregate using the
default window frame of UNBOUNDED PRECEDING to CURRENT ROW, with:
OVER REQUIRED
ORDER REQUIRED
WINDOW FRAME ALLOWED
RANGE NOT ALLOWED
48 SAP Sybase IQ
Scalar and Aggregate UDFs
The defaults for the all various options and restriction sets are:
DUPLICATE SENSITIVE
SQL SECURITY DEFINER
OVER ALLOWED
ORDER SENSITIVE
WINDOW FRAME ALLOWED
CURRENT ROW ALLOWED
PRECEDING ALLOWED
UNBOUNDED PRECEDING ALLOWED
FOLLOWING ALLOWED
UNBOUNDED FOLLOWING ALLOWED
• SQL Security – Defines whether the function is executed as the INVOKER, (the user who
is calling the function), or as the DEFINER (the user who owns the function). The default
is DEFINER.
When SQL SECURITY INVOKER is specified, more memory is used because each user that
calls the procedure requires annotation. Also, when SQL SECURITY INVOKER is
specified, name resolution is performed on both the user name and the INVOKER. Qualify
all object names (tables, procedures, and so on) with their appropriate owner.
• External Name – A function using the EXTERNAL NAME clause is a wrapper around a
call to a function in an external library. A function using EXTERNAL NAME can have no
other clauses following the RETURNS clause. The library name may include the file
extension, which is typically .dll on Windows and .so on UNIX. In the absence of the
extension, the software appends the platform-specific default file extension for libraries.
The EXTERNAL NAME clause is not supported for temporary functions.
The server can be started with a library load path that includes the location of the UDF library.
On UNIX variants, this can be done by modifying the LD_LIBRARY_PATH within the
start_iq startup script. While LD_LIBRARY_PATH is universal to all UNIX variants,
SHLIB_PATH is preferred on HP, and LIB_PATH is preferred on AIX.
On UNIX platforms, the external name specification can contain a fully qualified name, in
which case the LD_LIBRARY_PATH is not used. On the Windows platform, a fully qualified
name cannot be used and the library search path is defined by the PATH environment variable.
Note: Scalar user-defined functions and user-defined aggregate functions are not supported in
updatable cursors.
See also
• Defining an Aggregate UDF on page 53
• Context Storage of Aggregate User-Defined Functions on page 81
User-Defined Functions 49
Scalar and Aggregate UDFs
The various usage restrictions all default to ALLOWED to specify that this function can be
used anywhere in a SQL statement that any aggregate function is allowed.
Without any usage restrictions, my_sum is usable as a simple aggregate across an entire set of
rows, as shown here:
SELECT MIN(t.x), COUNT (*), my_sum(t.y)
FROM t
Without usage restrictions, my_sum is also usable as a simple aggregate computed for each
group as specified by a GROUP BY clause:
SELECT t.x, COUNT(*), my_sum(t.y)
FROM t
GROUP BY t.x
Because of the lack of usage restrictions, my_sum is usable as an OLAP-style aggregate with
an OVER clause, as shown in this cumulative summation example:
SELECT t.x,
my_sum(t.x)
OVER (ORDER BY t.x ROWS BETWEEN UNBOUNDED PRECEDING AND
CURRENT ROW)
AS cumulative_x,
COUNT(*)
FROM t
GROUP BY t.x
ORDER BY t.x
50 SAP Sybase IQ
Scalar and Aggregate UDFs
Like the my_sum example, my_bit_xor has no associated usage restrictions, and is therefore
usable as a simple aggregate or as an OLAP-style aggregate with any kind of a window.
Unlike the my_bit_xor example, the OVER NOT ALLOWED phrase in the declaration
restricts the use of this function to a simple aggregate. Because of that usage restriction,
my_bit_or is only usable as a simple aggregate across an entire set of rows, or as a simple
aggregate computed for each group as specified by a GROUP BY clause shown in the
following example:
SELECT t.x, COUNT(*), my_bit_or(t.y)
FROM t
GROUP BY t.x
User-Defined Functions 51
Scalar and Aggregate UDFs
To operate at a sensible cost, my_interpolate must run using a fixed-width, row-based window,
but the user can set the width of the window based on the maximum number of adjacent NULL
values he or she expects to see. This function takes a set of double-precision floating point
values and produces a resulting set of doubles.
The resulting UDAF declaration looks like this:
CREATE AGGREGATE FUNCTION my_interpolate (IN arg1 DOUBLE)
RETURNS DOUBLE
OVER REQUIRED
WINDOW FRAME REQUIRED
RANGE NOT ALLOWED
PRECEDING REQUIRED
UNBOUNDED PRECEDING NOT ALLOWED
FOLLOWING REQUIRED
UNBOUNDED FOLLOWING NOT ALLOWED
EXTERNAL NAME 'describe_my_interpolate@my_shared_lib'
OVER REQUIRED means that this function cannot be used as a simple aggregate (ON
EMPTY INPUT, if used, is irrelevant).
WINDOW FRAME details specify that you must use a fixed-width, row-based window that
extends both forward and backward from the current row when using this function. Because of
these usage restrictions, my_interpolate is usable as an OLAP-style aggregate with an OVER
clause similar to:
SELECT t.x,
my_interpolate(t.x)
OVER (ORDER BY t.x ROWS BETWEEN 5 PRECEDING AND 5 FOLLOWING)
AS x_with_gaps_filled,
COUNT(*)
FROM t
GROUP BY t.x
ORDER BY t.x
52 SAP Sybase IQ
Scalar and Aggregate UDFs
Within an OVER clause for my_interpolate, the precise number of preceding and following
rows may vary, and optionally, you can use a PARTITION BY clause; otherwise, the rows
must be similar to the example above given the usage restrictions in the declaration.
User-Defined Functions 53
Scalar and Aggregate UDFs
54 SAP Sybase IQ
Scalar and Aggregate UDFs
not share a context structure. Instead, individual sub-aggregates are treated exactly the
same as nonpartitioned aggregates. The independent super-aggregate sees a calling pattern
that looks like this:
_start_extfn
_reset_extfn
_next_subaggregate_extfn (repeated 0 to N times)
_evaluate_superaggregate_extfn
_finish_extfn
Or like this:
_start_extfn
_reset_extfn
_next_subaggregate_extfn (repeated 0 to N times)
_evaluate_superaggregate_extfn
_reset_extfn
_next_subaggregate_extfn (repeated 0 to N times)
_evaluate_superaggregate_extfn
_reset_extfn
_next_subaggregate_extfn (repeated 0 to N times)
_evaluate_superaggregate_extfn
_finish_extfn
See also
• Declaring an Aggregate UDF on page 47
• Context Storage of Aggregate User-Defined Functions on page 81
• Blob (a_v4_extfn_blob) on page 199
• Blob Input Stream (a_v4_extfn_blob_istream) on page 203
User-Defined Functions 55
Scalar and Aggregate UDFs
• _finish_extfn – required pointer to a shutdown function for which the only argument is a
pointer to a_v3_extfn_aggregate_context. Typically, used to deallocate some structure
with the address stored within the _user_data field in the a_v3_extfn_aggregate_context.
_finish_extfn is only ever called once per a_v3_extfn_aggregate_context.
void (*_finish_extfn)(a_v3_extfn_aggregate_context *);
• _reset_extfn – required pointer to a start-of-new-group function, for which the only
argument is a pointer to a_v3_extfn_aggregate_context. Typically, used to reset some
values in the structure for which the address was stashed within the _user_data field in the
a_v3_extfn_aggregate_context. _reset_extfn is called repeatedly.
void (*_reset_extfn)(a_v3_extfn_aggregate_context *);
• _next_value_extfn – required function pointer to be called for each new input set of
argument values. The function does not set the result of the aggregation. Access to input
argument values are through the get_value callback function and, if necessary, through
repeated calls to the get_piece callback function, which is required only if piece_len is less
than total_len.
void (*_next_value_extfn)(a_v3_extfn_aggregate_context *cntxt,
void *args_handle);
Note: The get_piece callback is valid in v3 and v4 scalar and aggregate UDFs. For v4 table
UDFs and TPFs, use the Blob (a_v4_extfn_blob) and Blob Input Stream
(a_v4_extfn_blob_istream) structures instead.
• _evaluate_extfn – required function pointer to be called to return the resulting aggregate
result value. _evaluate_extfn is sent to the server using the set_value callback function.
void (*_evaluate_extfn)(a_v3_extfn_aggregate_context *cntxt, void
*args_handle);
• _drop_value_extfn – Optional function pointer that is called for each input set of argument
values that has fallen out of a moving window frame. Do not use this function to set the
result of the aggregation. Access to input argument values are through the get_value
callback function and, if necessary, through repeated calls to the get_piece callback
function; however, access is required only if piece_len is less than total_len. Set
_drop_value_extfn to the null pointer if:
• The aggregate cannot be used with a window frame.
• The aggregate is not reversible in some way.
• The user is not interested in optimal performance.
Note: The get_piece callback is valid in v3 and v4 scalar and aggregate UDFs. For v4 table
UDFs and TPFs, use the Blob (a_v4_extfn_blob) and Blob Input Stream
(a_v4_extfn_blob_istream) structures instead.
If this function is not supplied, and the user has specified a moving window, then each time
the window frame moves, the reset function is called and each row now within the window
is included by a call to the next_value function. Finally, the evaluate function is called.
However, if this function is supplied, each time the window frame moves, this drop_value
function is called for each row falling out of the window frame, then the next_value
56 SAP Sybase IQ
Scalar and Aggregate UDFs
function is called for each row that has just been added into the window frame. Finally, the
evaluate function is called to produce the aggregate result.
void (*_drop_value_extfn)(a_v3_extfn_aggregate_context *cntxt,
void *args_handle);
• _evaluate_cumulative_extfn – optional function pointer to be called for each new input
set of argument values. If this function is supplied, and the usage is in a row-based window
frame that spans UNBOUNDED PRECEDING to CURRENT ROW, then this function is
called instead of next_value, immediately followed by calling evaluate.
_evaluate_cumulative_extfn must set the result of the aggregation through the set_value
callback. Access to input argument values are through the get_value callback function and,
if necessary, through repeated calls to the get_piece callback function, which is only
required if piece_len is less than total_len.
void (*_evaluate_cumulative_extfn)(a_v3_extfn_aggregate_context
*cntxt, void *args_handle);
Note: The get_piece callback is valid in v3 and v4 scalar and aggregate UDFs. For v4 table
UDFs and TPFs, use the Blob (a_v4_extfn_blob) and Blob Input Stream
(a_v4_extfn_blob_istream) structures instead.
• _next_subaggregate_extfn – optional callback function pointer that, with the
_evaluate_superaggregate_extfn function (and in some usages also with the
_drop_subaggregate_extfn function), enables some usages of the aggregate to be
optimized through parallel and partial results aggregation.
Some aggregates, when used as simple aggregates (in other words, not OLAP-style
aggregates with an OVER clause) can be partitioned by first producing a set of
intermediate aggregate results where each of the intermediate results is computed from a
disjoint subset of the input rows. Examples of such partitionable aggregates include:
• SUM, where the final SUM can be computed by performing a SUM for each disjoint
subset of the input rows and then performing a SUM over the sub-SUMs; and
• COUNT(*), where the final COUNT can be computed by performing a COUNT for
each disjoint subset of the input rows and then performing a SUM over the COUNTs
from each partition.
When an aggregate satisfies the above conditions, the server may choose to make the
computation of that aggregate parallel. For aggregate UDFs, this optimization can be
applied only if both the _next_subaggregate_extfn callback and the
_evaluate_superaggregate_extfn callback are supplied. This usage pattern does not
require _drop_subaggregate_extfn.
Similarly, if an aggregate can be used with a RANGE-based OVER clause, an optimization
can be applied if _next_subaggregate_extfn, _drop_subaggregate_extfn, and
_evaluate_superaggregate_extfn) functions are all supplied by the Aggregate UDF
implementation.
_next_subaggregate_extfn does not set the final result of the aggregation, and by
definition, has exactly one input argument value that is the same data type as the return
value of the aggregate UDF. Access to the sub-aggregate input value is through the
User-Defined Functions 57
Scalar and Aggregate UDFs
get_value callback function and, if necessary, through repeated calls to the get_piece
callback function, which is required only if piece_len is less than total_len.
Note: The get_piece callback is valid in v3 and v4 scalar and aggregate UDFs. For v4 table
UDFs and TPFs, use the Blob (a_v4_extfn_blob) and Blob Input Stream
(a_v4_extfn_blob_istream) structures instead.
Direct communication between sub-aggregates and the super-aggregate is impossible; the
server handles all such communication. The sub-aggregates and the super-aggregate do
not share the context structure. Individual sub-aggregates are treated exactly the same as
nonpartitioned aggregates. The independent super-aggregate sees a calling pattern that
looks like this:
_start_extfn
_reset_extfn
_next_subaggregate_extfn (repeated 0 to N times)
_evaluate_superaggregate_extfn
_finish_extfn
void (*_next_subaggregate_extfn)(a_v3_extfn_aggregate_context
*cntxt, void *args_handle);
• _drop_subaggregate_extfn – optional callback function pointer that, together with
_next_subaggregate_extfn and _evaluate_superaggregate_extfn, enables some usages
involving RANGE-based OVER clauses to be optimized through a partial aggregation.
_drop_subaggregate_extfn is called whenever a set of rows sharing a common ordering
key value have collectively fallen out of a moving window. This optimization is applied
only if all three functions are provided by the UDF.
void (*_drop_subaggregate_extfn)(a_v3_extfn_aggregate_context
*cntxt, void *args_handle);
• _evaluate_superaggregate_extfn – optional callback function pointer that, together with
_next_subaggregate_extfn (and in some cases also with _drop_subaggregate_extfn),
enables some usages to be optimized by running in parallel.
_evaluate_superaggregate_extfn is called, as described above, when it is time to return the
result of a partitioned aggregate. The result value is sent to the server using the set_value
callback function from the a_v3_extfn_aggregate_context structure:
void (*_evaluate_superaggregate_extfn)
(a_v3_extfn_aggregate_context *cntxt, void *args_handle);
• NULL fields – initialize these fields to NULL:
void * reserved1_must_be_null;
void * reserved2_must_be_null;
void * reserved3_must_be_null;
void * reserved4_must_be_null;
void * reserved5_must_be_null;
• Status indicator bit field – a bit field containing indicators that allow the engine to
optimize the algorithm used to process the aggregate.
a_sql_uint32 indicators;
• _calculation_context_size – the number of bytes for the server to allocate for each UDF
calculation context. The server may allocate multiple calculation contexts during query
58 SAP Sybase IQ
Scalar and Aggregate UDFs
See also
• Blob (a_v4_extfn_blob) on page 199
• Blob Input Stream (a_v4_extfn_blob_istream) on page 203
Calculation Context
The _user_calculation_context field allows the server to concurrently execute calculations on
multiple groups of data.
An Aggregate UDF must keep intermediate counters for calculations as it is processing rows.
The simple model for managing these counters is to allocate memory at the start API function,
store a pointer to it in the aggregate context's _user_data field, then release the memory at the
aggregate's finish API. An alternative method, based on the _user_calculation_context field,
allows the server to concurrently execute calculations on multiple groups of data.
The _user_calculation_context field is a server-allocated memory pointer, created by the
server for each concurrent processing group. The server ensures that the
_user_calculation_context always points to the correct calculation context for the group of
rows currently being processed. Between UDF API calls, depending on the data, the server
User-Defined Functions 59
Scalar and Aggregate UDFs
may allocate new _user_calculation_context values. The server may save and restore
calculation context areas to disk while processing a query.
The UDF stores all intermediate calculation values in this field. This illustrates a typical
usage:
struct my_average_context
{
int sum;
int count;
};
reset(a_v3_aggregate_context *context)
{
mycontext = (my_average_context *) context-
>_user_calculation_context;
mycontext->count = 0;
mycontext->sum = 0;
}
In this model, the _user_data field can still be used, but no values relating to intermediate result
calculations can be stored there. The _user_calculation_context is NULL at both the start and
finish entry points.
To use the _user_calculation_context to enable concurrent processing, the UDF must specify
the size and alignment requirements for its calculation context, and define a structure to hold
its values and set a_v3_extfn_aggregate and _calculation_context_size to the sizeof() of that
structure.
The UDF must also specify the data alignment requirements of _user_calculation_context
through _calculation_context_alignment. If user_calculation_context memory contains only
a character byte array, no particular alignment is necessary, and you can specify an alignment
of 1. Likewise, double floating point values might require an 8-byte alignment. Alignment
requirements vary by platform and data type. Specifying a larger alignment than necessary
always works; however, using the smallest alignment uses memory more efficiently.
60 SAP Sybase IQ
Scalar and Aggregate UDFs
functions specified within the aggregate UDF descriptor structure when they are called. The
aggregate context structure is defined as:
• typedef struct a_v3_extfn_aggregate_context – One created for each instance of an
external function referenced within a query. If used within a parallelized subtree within a
query, there is a separate context for parallel subtree.
• Callbacks available via the context – Common arguments to the callback routines
include:
• arg_handle – A handle to function instance and arguments provided by the server.
• arg_num – The argument number. Return values are 0..N.
• data – The pointer to argument data.
The context must call get_value before get_piece, but needs to call get_piece only if
piece_len is less than total_len.
short (SQL_CALLBACK *get_value)(
void * arg_handle,
a_sql_uint32 arg_num,
an_extfn_value *value
);
short (SQL_CALLBACK *get_piece)(
void * arg_handle,
a_sql_uint32 arg_num,
an_extfn_value *value,
a_sql_uint32 offset
);
• Determining whether an argument is a constant – The UDF can ask whether a given
argument is a constant. This can be useful, for example, to allow work to be done once at
the first call to the _next_value function rather than for every call to the _next_value
function.
short (SQL_CALLBACK *get_value_is_constant)(
void * arg_handle,
a_sql_uint32 arg_num,
a_sql_uint32 * value_is_constant
);
• Returning a null value – To return a null value, set "data" to NULL in an_extfn_value. The
total_len field is ignored on calls to set_value, the data supplied becomes the value of the
argument if append is FALSE; otherwise, the data is appended to the current value of the
argument. It is expected that set_value is called with append=FALSE for an argument
before being called with append=TRUE for the same argument. The append field is
ignored for fixed-length data types (in other words, all numeric data types).
short (SQL_CALLBACK *set_value)(
void * arg_handle,
an_extfn_value *value,
short append
);
• Determining whether the statement was interrupted – If a UDF entry point performs
work for an extended period of time (many seconds), then it should, if possible, call the
get_is_cancelled callback every second or two to see if the user has interrupted the current
statement. If the statement has been interrupted, a nonzero value is returned, and the UDF
User-Defined Functions 61
Scalar and Aggregate UDFs
entry point should then immediately perform. Eventually, the _finish_extfn function is
called to do any necessary cleanup, but no other UDF entry points are subsequently called.
a_sql_uint32 (SQL_CALLBACK *get_is_cancelled)
(a_v3_extfn_aggregate_context * cntxt);
• Sending error messages – If a UDF entry point encounters some error that should result
in an error message being sent back to the user and the current statement being shut down,
the set_error callback routine should be called. set_error causes the current statement to
roll back; the user sees Error from external UDF: <error_desc_string>,
and the SQLCODE is the negated form of <error_number>. After a call to set_error, the
UDF entry point immediately performs a return. Eventually, _finish_extfn is called to
perform any necessary cleanup, but no other UDF entry points are subsequently called.
void (SQL_CALLBACK *set_error)(
a_v3_extfn_aggregate_context * cntxt,
a_sql_uint32 error_number,
// use error_number values >17000 & <100000
const char * error_desc_string
);
• Writing messages to the message log – Messages longer than 255 bytes may be
truncated.
void (SQL_CALLBACK *log_message)(
const char *msg,
short msg_length
);
• Converting one data type to another – for input:
• an_extfn_value.data – input data pointer.
• an_extfn_value.total_len – length of input data.
• an_extfn_value.type – DT_ datatype of input.
For output:
• an_extfn_value.data – UDF-supplied output data pointer.
• an_extfn_value.piece_len – maximum length of output data.
• an_extfn_value.total_len – server set length of converted output.
• an_extfn_value.type – DT_ datatype of desired output.
short (SQL_CALLBACK *convert_value)(
an_extfn_value *input,
an_extfn_value *output
);
• Fields reserved for future use – These are reserved for future use:
void * reserved1;
void * reserved2;
void * reserved3;
void * reserved4;
void * reserved5;
• Data available from the context – This data pointer can be filled in by any usage with any
context data the external routine requires. The UDF allocates and deallocates this memory.
A single instance of _user_data is active for each statement. Do not use this memory for
intermediate result values.
62 SAP Sybase IQ
Scalar and Aggregate UDFs
void * _user_data;
• Currently active calculation context – UDFs should use this memory location to store
intermediate values that calculate the aggregate. This memory is allocated by the server
based on the size requested in the a_v3_extfn_aggregate. Intermediate calculations must
be stored in this memory, since the engine may perform simultaneous calculations over
more than one group. Before each UDF entry point, the server ensures that the correct
context data is active.
void * _user_calculation_context;
• Other available aggregate information – Available at all external function entry points,
including start_extfn. Zero indicates an unknown or not-applicable value. Estimated
average number of rows per partition or group.
• a_sql_uint64 _max_rows_in_frame; – Calculates the maximum number of rows
defined in the window frame. For range-based windows, this indicates unique values.
Zero indicates an unknown or not-applicable value.
• a_sql_uint64 _estimated_rows_per_partition; – Displays the estimated average
number of rows per partition or group. 0 indicates an unknown or not-applicable value.
• a_sql_uint32 _is_used_as_a_superaggregate; – Identifies whether this instance is a
normal aggregate or a superaggregate. Returns a result of 0 if the instance is a normal
aggregate.
• Determining window specifications – Window specifications if a window is present on
the query:
• a_sql_uint32 _is_window_used; – Determines if the statement is windowed.
• a_sql_uint32 _window_has_unbounded_preceding; – A return value of 0 indicates
the window does not have unbounded preceding.
• a_sql_uint32 _window_contains_current_row; – A return value of 0 indicates the
window does not contain the current row.
• a_sql_uint32 _window_is_range_based; – If the return code is 1, the window is
range-based. If the return code is 0, the window is row-based.
• Available at reset_extfn() calls – Returns the actual number of rows in current partition, or
0 for nonwindowed aggregate.
a_sql_uint64 _num_rows_in_partition;
• Available only at evaluate_extfn() calls for windowed aggregates – Currently evaluated
row number in partition (starting with 1). This is useful during the evaluation phase of
unbounded windows.
a_sql_uint64 _result_row_from_start_of_partition;
• Closing syntax – Complete the context with:
//---------- For Server Internal Use Only ----------
void * _for_server_internal_use;
} a_v3_extfn_aggregate_context;
User-Defined Functions 63
Scalar and Aggregate UDFs
See also
• Blob (a_v4_extfn_blob) on page 199
• Blob Input Stream (a_v4_extfn_blob_istream) on page 203
64 SAP Sybase IQ
Scalar and Aggregate UDFs
extern "C"
void my_integer_sum_start(a_v3_extfn_aggregate_context *cntxt)
{
}
extern "C"
void my_integer_sum_finish(a_v3_extfn_aggregate_context *cntxt)
{
}
extern "C"
void my_integer_sum_reset(a_v3_extfn_aggregate_context *cntxt)
{
my_total *cptr = (my_total *)cntxt->_user_calculation_context;
cptr->_total = 0;
cptr->_num_nonnulls_seen = 0;
}
extern "C"
void my_integer_sum_next_value(a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value arg;
a_sql_int32 arg1;
// Get the one argument, and if non-NULL then add it to the total
//
if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) {
arg1 = *((a_sql_int32 *)arg.data);
cptr->_total += arg1;
cptr->_num_nonnulls_seen++;
}
}
extern "C"
void my_integer_sum_drop_value(a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value arg;
a_sql_int32 arg1;
my_total *cptr = (my_total *)cntxt->_user_calculation_context;
// Get the one argument, and if non-NULL then subtract it from the
total
User-Defined Functions 65
Scalar and Aggregate UDFs
extern "C"
void my_integer_sum_evaluate(a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value outval;
my_total *cptr = (my_total *)cntxt->_user_calculation_context;
extern "C"
void my_integer_sum_cum_evaluate(
a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value outval;
an_extfn_value arg;
int arg1;
my_total *cptr = (my_total *)cntxt->_user_calculation_context;
// Get the one argument, and if non-NULL then add it into the
total.
//
if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) {
arg1 = *((a_sql_int32 *)arg.data);
cptr->_total += arg1;
cptr->_num_nonnulls_seen++;
}
66 SAP Sybase IQ
Scalar and Aggregate UDFs
outval.data = 0;
}
cntxt->set_value( arg_handle, &outval, 0 );
}
extern "C"
void my_integer_sum_next_subagg_value(
a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value arg;
a_sql_int64 arg1;
// Get the one argument, and if non-NULL then add it to the total
//
if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) {
arg1 = *((a_sql_int64 *)arg.data);
cptr->_total += arg1;
cptr->_num_nonnulls_seen++;
}
}
extern "C"
void my_integer_sum_drop_subagg_value(
a_v3_extfn_aggregate_context *cntxt,
void *arg_handle)
{
an_extfn_value arg;
a_sql_int64 arg1;
// Get the one argument, and if non-NULL then subtract it from the
total
//
if (cntxt->get_value( arg_handle, 1, &arg) && arg.data) {
arg1 = *((a_sql_int64 *)arg.data);
cptr->_total -= arg1;
cptr->_num_nonnulls_seen--;
}
}
a_v3_extfn_aggregate my_integer_sum_descriptor =
{
&my_integer_sum_start,
&my_integer_sum_finish,
&my_integer_sum_reset,
&my_integer_sum_next_value,
&my_integer_sum_evaluate,
&my_integer_sum_drop_value,
User-Defined Functions 67
Scalar and Aggregate UDFs
&my_integer_sum_cum_evaluate,
&my_integer_sum_next_subagg_value,
&my_integer_sum_drop_subagg_value,
&my_integer_sum_evaluate,
NULL, // reserved1_must_be_null
NULL, // reserved2_must_be_null
NULL, // reserved3_must_be_null
NULL, // reserved4_must_be_null
NULL, // reserved5_must_be_null
0, // indicators
( short )sizeof( my_total ), // context size
8, // context alignment
0.0, //external_bytes_per_group
0.0, // external bytes per row
0, // reserved6_must_be_null
0, // reserved7_must_be_null
0, // reserved8_must_be_null
0, // reserved9_must_be_null
0, // reserved10_must_be_null
NULL // _for_server_internal_use
};
extern "C"
a_v3_extfn_aggregate *my_integer_sum()
{
return &my_integer_sum_descriptor;
}
68 SAP Sybase IQ
Scalar and Aggregate UDFs
User-Defined Functions 69
Scalar and Aggregate UDFs
an_extfn_value arg;
a_sql_uint32 arg1;
my_xor_result *cptr = (my_xor_result *)cntxt-
>_user_calculation_context;
outval.type = DT_UNSINT;
outval.piece_len = sizeof(a_sql_uint32);
if (cptr->_num_nonnulls_seen > 0) {
outval.data = &cptr->_xor_result;
} else {
outval.data = 0;
}
cntxt->set_value( arg_handle, &outval, 0 );
}
70 SAP Sybase IQ
Scalar and Aggregate UDFs
} else {
outval.data = 0;
}
cntxt->set_value( arg_handle, &outval, 0 );
}
a_v3_extfn_aggregate *my_bit_xor()
{
return &my_xor_descriptor;
}
User-Defined Functions 71
Scalar and Aggregate UDFs
#include "extfnapiv4.h"
#include <stdlib.h>
#include <assert.h>
72 SAP Sybase IQ
Scalar and Aggregate UDFs
a_sql_uint32 arg1;
outval.type = DT_UNSINT;
outval.piece_len = sizeof(a_sql_uint32);
if (cptr->_non_null_seen)
{
outval.data = &cptr->_or_result;
}
else
{
// Return null if no values seen
outval.data = 0;
}
cntxt->set_value( arg_handle, &outval, 0 );
}
User-Defined Functions 73
Scalar and Aggregate UDFs
extern "C"
a_v3_extfn_aggregate *my_bit_or()
{
return &my_or_descriptor;
}
// MY_INTERPOLATE
//
// OLAP-style aggregate UDF that accepts a double precision
// floating point argument. If the current argument value is
// not NULL, then the result value is the same as the
// argument value. On the other hand, if the current row's
// argument value is NULL, then the result, where possible,
// will be the arithmetic interpolation across the nearest
// preceding and nearest following values that are not NULL.
// In all cases the result is also a double precision value.
//
// The start function creates a structure for maintaining the
// argument values within the window including their NULLness.
74 SAP Sybase IQ
Scalar and Aggregate UDFs
cptr->_first_used = 0;
cptr->_next_insert_loc = 0;
cptr->_num_rows_in_frame = 0;
for (int i=0; i<cptr->_allocated_elem; i++) {
cptr->_is_null[i] = 1;
}
}
User-Defined Functions 75
Scalar and Aggregate UDFs
if (!cntxt->_is_window_used)
{
cntxt->set_error(cntxt, 20001, "Function requires window");
return;
}
if (cntxt->_window_has_unbounded_preceding ||
cntxt->_window_has_unbounded_following)
{
cntxt->set_error(cntxt, 20002, "Window cannot be unbounded");
return;
}
if (cntxt->_window_is_range_based)
{
cntxt->set_error(cntxt, 20003, "Window must be row based");
return;
}
if (!cptr) {
//
cptr = (my_window *)malloc(sizeof(my_window));
if (cptr) {
cptr->_is_null = 0;
cptr->_dbl_val = 0;
cptr->_num_rows_in_frame = 0;
cptr->_allocated_elem = ( int )cntxt->_max_rows_in_frame;
cptr->_is_null = (int *)malloc(cptr->_allocated_elem
* sizeof(int));
cptr->_dbl_val = (double *)malloc(cptr->_allocated_elem
* sizeof(double));
cntxt->_user_data = cptr;
}
}
if (!cptr || !cptr->_is_null || !cptr->_dbl_val) {
// Terminate this query
cntxt->set_error(cntxt, 20000, "Unable to allocate memory");
return;
}
my_interpolate_reset(cntxt);
}
76 SAP Sybase IQ
Scalar and Aggregate UDFs
}
}
an_extfn_value outval;
my_window *cptr = (my_window *)cntxt->_user_data;
double result;
int result_is_null = 1;
User-Defined Functions 77
Scalar and Aggregate UDFs
double preceding_value;
int preceding_value_is_null = 1;
double preceding_distance = 0;
double following_value;
int following_value_is_null = 1;
double following_distance = 0;
int j;
78 SAP Sybase IQ
Scalar and Aggregate UDFs
User-Defined Functions 79
Scalar and Aggregate UDFs
result_is_null = 0;
}
}
a_v3_extfn_aggregate *my_interpolate()
{ return &my_interpolate_descriptor; }
80 SAP Sybase IQ
Scalar and Aggregate UDFs
See also
• Declaring an Aggregate UDF on page 47
• Defining an Aggregate UDF on page 53
User-Defined Functions 81
Scalar and Aggregate UDFs
fullname (Employees.GivenName,Employees.SurName)
Fran Whitney
Matthew Cobb
Philip Chin
...
The following statement returns a full name from a supplied first and last name:
SELECT fullname ('Jane', 'Smith');
fullname ('Jane','Smith')
Jane Smith
Any user who has been granted Execute permissions for the function can use the fullname
function.
82 SAP Sybase IQ
Scalar and Aggregate UDFs
• set_value – The function used within an evaluation function to tell the server the result
value of the UDF for this call. If the result data type is narrow, one call to set_value is
sufficient. However, if the result data value is wide, then multiple calls to set_value are
required to pass the entire value, and the append argument to the callback should be true for
each fragment except the last. To return a NULL result, the UDF should set the data field
within the result value's an_extfn_value structure to the null pointer.
• get_is_cancelled – A function to determine whether the statement has been cancelled. If a
UDF entry point is performing work for an extended period of time (many seconds), then it
should, if possible, call the get_is_cancelled callback every second or two to see if the user
has interrupted the current statement. The return value is 0 if the statement has not been
interrupted.
SAP Sybase IQ can handle extremely large data sets, and some queries can run for long
periods of time. Occasionally, a query takes an unusually long time to execute. The SQL
client lets the user cancel a query if it is taking too long to complete. Native functions track
when a user has canceled a query. UDFs must also be written in a manner that tracks
whether a query has been canceled by the user. In other words, UDFs should support the
ability for users to cancel long-running queries that invoke UDFs.
• set_error – A function that can be used to communicate an error back to the server, and
eventually to the user. Call this callback routine if a UDF entry point encounters an error
that should result in an error message being sent back to the user. When called, set_error
rolls back the current statement, and the user receives Error from external UDF:
error_desc_string, and the SQLCODE is the negated form of the supplied
error_number. To avoid collisions with existing errors, UDFs should use error_number
values between 17000 and 99999. The maximum length of “error_desc_string” is 140
characters.
• log_message – The function used to send a message to the server's message log. The string
must be a printable text string no longer than 255 bytes.
• convert_value – The function allows data conversion between data types. The primary use
is the conversion between DT_DATE, DT_TIME, and DT_TIMESTAMP, and
DT_TIMESTAMP_STRUCT. An input and output an_extfn_value is passed to the
function.
See also
• Scalar UDF Calling Pattern on page 84
• Aggregate UDF Calling Patterns on page 84
• Blob (a_v4_extfn_blob) on page 199
• Blob Input Stream (a_v4_extfn_blob_istream) on page 203
User-Defined Functions 83
Scalar and Aggregate UDFs
See also
• Scalar and Aggregate UDF Callback Functions on page 82
• Aggregate UDF Calling Patterns on page 84
See also
• Scalar and Aggregate UDF Callback Functions on page 82
• Scalar UDF Calling Pattern on page 84
Query
select my_sum(a) from t
84 SAP Sybase IQ
Scalar and Aggregate UDFs
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) -- input a=1
_next_value_extfn(cntxt, args) -- input a=2
_next_value_extfn(cntxt, args) -- input a=3
_next_value_extfn(cntxt, args) -- input a=4
_next_value_extfn(cntxt, args) -- input a=5
_next_value_extfn(cntxt, args) -- input a=6
_evaluate_extfn(cntxt, args) -- returns 21
_finish_extfn(cntxt)
Result
my_sum(a)
21
Query
select b, my_sum(a) from t group by b order by b
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) -- input a=1
_next_value_extfn(cntxt, args) -- input a=2
_next_value_extfn(cntxt, args) -- input a=3
_evaluate_extfn(cntxt, args) -- returns 6
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) -- input a=4
_next_value_extfn(cntxt, args) -- input a=5
_next_value_extfn(cntxt, args) -- input a=6
_evaluate_extfn(cntxt, args) -- returns 15
_finish_extfn(cntxt)
Result
b, my_sum(a)
1, 6
2, 15
User-Defined Functions 85
Scalar and Aggregate UDFs
Query
select b, my_sum(a) over (partition by b rows between
unbounded preceding and
unbounded following)
from t
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=1
_next_value_extfn(cntxt, args) input a=2
_next_value_extfn(cntxt, args) input a=3
_evaluate_extfn(cntxt, args) rr=1 returns 6
_evaluate_extfn(cntxt, args) rr=2 returns 6
_evaluate_extfn(cntxt, args) rr=3 returns 6
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=4
_next_value_extfn(cntxt, args) input a=5
_next_value_extfn(cntxt, args) input a=6
_evaluate_extfn(cntxt, args) rr=1 returns 15
_evaluate_extfn(cntxt, args) rr=2 returns 15
_evaluate_extfn(cntxt, args) rr=3 returns 15
_finish_extfn(cntxt)
Result
b, my_sum(a)
1, 6
1, 6
1, 6
2, 15
2, 15
2, 15
Query
select b, my_sum(a) over (partition by b
rows between unbounded preceding and current row)
from t
order by b
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) -- input a=1
86 SAP Sybase IQ
Scalar and Aggregate UDFs
Result
b, my_sum(a)
1, 1
1, 3
1, 6
2, 4
2, 9
2, 15
Query
select b, my_sum(a) over (partition by b rows between unbounded
preceding and current row)
from t
order by b
Calling pattern
_start_extnfn(cntxt)
_reset_extfn(cntxt)
_evaluate_cumulative_extfn(cntxt, args) -- input a=1 returns 1
_evaluate_cumulative_extfn(cntxt, args) -- input a=2 returns 3
_evaluate_cumulative_extfn(cntxt, args) -- input a=3 returns 6
_reset_extfn(cntxt)
_evaluate_cumulative_extfn(cntxt, args) -- input a=4 returns 4
_evaluate_cumulative_extfn(cntxt, args) -- input a=5 returns 9
_evaluate_cumulative_extfn(cntxt, args) -- input a=6 returns 15
_finish_extfn(cntxt)
Result
b, my_sum(a)
1, 1
1, 3
1, 6
User-Defined Functions 87
Scalar and Aggregate UDFs
2, 4
2, 9
2, 15
Query
select b, my_sum(a) over (partition by b rows between 1 preceding and
current row)
from t
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=1
_evaluate_extfn(cntxt, args) returns 1
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=1
_next_value_extfn(cntxt, args) input a=2
_evaluate_extfn(cntxt, args) returns 3
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args ) input a=2
_next_value_extfn(cntxt, args ) input a=3
_evaluate_extfn(cntxt, args) returns 5
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=4
_evaluate_extfn(cntxt, args) returns 4
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=4
_next_value_extfn(cntxt, args) input a=5
_evaluate_extfn(cntxt, args) returns 9
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=5
_next_value_extfn(cntxt, args) input a=6
_evaluate_extfn(cntxt, args) returns 11
_finish_extfn(cntxt)
Result
b, my_sum(a)
1, 1
1, 3
1, 5
2, 4
2, 9
2, 11
88 SAP Sybase IQ
Scalar and Aggregate UDFs
Query
select b, my_sum(a) over (partition by b rows between 1 preceding and
current row)
from t
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_evaluate_aggregate_extfn(cntxt, args) -- returns 1
_evaluate_aggregate_extfn(cntxt, args) -- returns 3
_drop_value_extfn(cntxt) -- input a=1
_next_value_extfn(cntxt, args) -- input a=3
_evaluate_aggregate_extfn(cntxt, args) -- returns 5
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) -- input a=4
_evaluate_aggregate_extfn(cntxt, args) -- returns 4
_next_value_extfn(cntxt, args) -- input a=5
_evaluate_aggregate_extfn(cntxt, args) -- returns 9
_drop_value_extfn(cntxt) -- input a=4
_next_value_extfn(cntxt, args) -- input a=6
_evaluate_aggregate_extfn(cntxt, args) -- returns 11
_finish_extfn(cntxt)
Result
b, my_sum(a)
1, 1
1, 3
1, 5
2, 4
2, 9
2, 11
Query
select b, my_sum(a) over (partition by b rows between 1 preceding and
1 following)
from t
User-Defined Functions 89
Scalar and Aggregate UDFs
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=1
_next_value_extfn(cntxt, args) input a=2
_evaluate_extfn(cntxt, args) returns 3
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=1
_next_value_extfn(cntxt, args) input a=2
_next_value_extfn(cntxt, args) input a=3
_evaluate_extfn(cntxt, args) returns 6
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=2
_next_value_extfn(cntxt, args) input a=3
_evaluate_extfn(cntxt, args) returns 5
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=4
_next_value_extfn(cntxt, args) input a=5
_evaluate_extfn(cntxt, args) returns 9
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=4
_next_value_extfn(cntxt, args) input a=5
_next_value_extfn(cntxt, args) input a=6
_evaluate_extfn(cntxt, args) returns 15
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=5
_next_value_extfn(cntxt, args) input a=6
_evaluate_extfn(cntxt, args) returns 11
_finish_extfn(cntxt)
Result
b, my_sum(a)
1, 3
1, 6
1, 5
2, 9
2, 15
2, 11
Query
select b, my_sum(a) over (partition by b rows between 1 preceding and
1 following)
from t
90 SAP Sybase IQ
Scalar and Aggregate UDFs
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=1
_next_value_extfn(cntxt, args) input a=2
_evaluate_extfn(cntxt, args) returns 3
_next_value_extfn(cntxt, args) input a=3
_evaluate_extfn(cntxt, args) returns 6
_dropvalue_extfn(cntxt) input a=1
_evaluate_extfn(cntxt, args) returns 5
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=4
_next_value_extfn(cntxt, args) input a=5
_evaluate_extfn(cntxt, args) returns 9
_next_value_extfn(cntxt, args) input a=6
_evaluate_extfn(cntxt, args) returns 15
_dropvalue_extfn(cntxt) input a=4
_evaluate_extfn(cntxt, args) returns 11
_finish_extfn(cntxt)
Result
b, my_sum(a)
1, 3
1, 6
1, 5
2, 9
2, 15
2, 11
Query
select b, my_sum(a) over (rows between 3 preceding and 1 preceding)
from t
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_evaluate_extfn(cntxt, args) returns NULL
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=1
_evaluate_extfn(cntxt, args) returns 1
_reset_extfn(cntxt)
_next_value_extfn(cntxt, args) input a=1
_next_value_extfn(cntxt, args) input a=2
User-Defined Functions 91
Scalar and Aggregate UDFs
Result
b my_sum(a)
----------- -------------
1 NULL
1 1
1 3
2 6
2 9
2 12
Query
select b, my_sum(a) over (rows between 3 preceding and 1 preceding)
from t
Calling pattern
_start_extfn(cntxt)
_reset_extfn(cntxt)
_evaluate_extfn(cntxt, args) returns NULL
_next_value_extfn(cntxt, args) input a=1
_evaluate_extfn(cntxt, args) returns 1
_next_value_extfn(cntxt, args) input a=2
_evaluate_extfn(cntxt, args) returns 3
_next_value_extfn(cntxt, args) input a=3
_evaluate_extfn(cntxt, args) returns 6
_dropvalue_extfn(cntxt) input a=1
_next_value_extfn(cntxt, args) input a=4
_evaluate_extfn(cntxt, args) returns 9
_dropvalue_extfn(cntxt) input a=2
_next_value_extfn(cntxt, args) input a=5
92 SAP Sybase IQ
Scalar and Aggregate UDFs
Result
b my_sum(a)
---------- -------------
1 NULL
1 1
1 3
2 6
2 9
2 12
This function returns an unsigned 32-bit integer. If the return value is nonzero, the database
server assumes that you are using the new API.
If the DLL does not export this function, the database server assumes that the old API is in use.
When using the new API, the returned value must be the API version number defined in
extfnapi.v4h.
The presence of this function, and that it returns EXTFN_V4_API informs the SAP Sybase IQ
engine that the library contains UDFs written to the new API documented in this book.
Function prototypes
The name of the function must match that referenced in the CREATE PROCEDURE or
CREATE FUNCTION statement. Declare the function as:
void function-name ( an_extfn_api *api, void *argument-handle )
The function must return void, and must take as arguments a structure used to pass the
arguments, and a handle to the arguments provided by the SQL procedure.
The an_extfn_api structure has this form:
User-Defined Functions 93
Scalar and Aggregate UDFs
Note: The get_piece callback is valid in v3 and v4 scalar and aggregate UDFs. For v4 table
UDFs and TPFs, use the Blob (a_v4_extfn_blob) and Blob Input Stream
(a_v4_extfn_blob_istream) structures instead.
The an_extfn_value structure has this form:
typedef struct an_extfn_value {
void * data;
a_sql_uint32 piece_len;
union {
a_sql_uint32 total_len;
a_sql_uint32 remain_len;
} len;
a_sql_data_type type;
} an_extfn_value;
Notes
Calling get_value on an OUT parameter returns the data type of the argument, and returns
data as NULL.
The get_piece function for any given argument can be called only immediately after the
get_value function for the same argument.
To return NULL, set data to NULL in an_extfn_value.
The append field of set_value determines whether the supplied data replaces (false) or
appends to (true) the existing data. You must call set_value with append=FALSE before
calling it with append=TRUE for the same argument. The append field is ignored for fixed-
length data types.
94 SAP Sybase IQ
Scalar and Aggregate UDFs
See also
• Blob (a_v4_extfn_blob) on page 199
• Blob Input Stream (a_v4_extfn_blob_istream) on page 203
User-Defined Functions 95
Scalar and Aggregate UDFs
96 SAP Sybase IQ
Table UDFs and TPFs
See also
• Table Parameterized Functions on page 136
• Declaring and Defining Scalar User-Defined Functions on page 32
• Declaring and Defining Aggregate UDFs on page 46
• Learning Roadmap: Types of External C and C++ UDFs on page 6
• Creating a Java Table UDF on page 354
User Roles
Two types of users work with table UDFs: UDF developers, and SQL analysts.
• UDF developer – develops the table UDF in C or C++.
• SQL analyst – develops and analyzes the SQL queries that reference the table expression
in the FROM clause. The table expression is the set of rows produced by the table UDF.
See also
• Learning Roadmap for Table UDF Developers on page 97
• Learning Roadmap for SQL Analysts on page 98
User-Defined Functions 97
Table UDFs and TPFs
Task See
Become familiar with table UDF and TPF re- Table UDF Restrictions on page 99
strictions.
Create a table UDF. Developing a Table UDF on page 103
(Optional) Define the library version validators Library Version (extfn_get_library_version) on
for distributed query processing (DQP). page 17
Library Version Compatibility (extfn_check_ver-
sion_compatibility) on page 17
Compile and link source code. Compile and Link Source Code to Build Dynam-
ically Linkable Libraries on page 19
Declare the UDF to the server using the CREATE Learning Roadmap for SQL Analysts on page
PROCEDURE statement. Write and execute these 98
statements as commands, or use Sybase Control
Center.
98 SAP Sybase IQ
Table UDFs and TPFs
See also
• SQL Reference for Table UDF and TPF Queries on page 166
Get Started
Familiarize yourself with sample files, concepts, and restrictions before developing table
UDFs and TPFs.
Sample Files
Sample table UDF files are installed with the server. Use the samples as models when defining
your own table UDFs.
Sample files are located in:
• %ALLUSERSPROFILE%\SybaseIQ\samples\udf (Windows)
• $SYBASE/IQ-16_0/samples/udf (UNIX)
User-Defined Functions 99
Table UDFs and TPFs
File Description
apache_log_reader.cxx Implementation of a table UDF that reads an
Apache log file and presents the rows from the file
in table format. This UDF illustrates a real-world
example of how you can use a UDF to make
computer-generated data available to a SQL
query writer in real time.
build.sh / build.bat Script that compiles and links the sample scalar
and aggregate UDFs, table UDFs, and TPFs
found in the samples/udf directory.
File Description
udf_main.cxx This file is linked into all of the examples and
includes a common set of required entry points
for the v4 API. This allows you to reuse the code
rather than including it in each example.
udf_rg_1.cxx A simple table UDF that generates rows of integer
data.
udf_rg_2.cxx A simple table UDF that generates rows of integer
data that uses describes to ensure the sche-
ma defined in SQL matches the UDF's imple-
mentation. It also describes some optimizer at-
tributes.
udf_rg_3.cxx A simple table UDF that generates integer data in
blocks of 100 using the _fetch_block fetch
method.
udf_utils.cxx A set of utility functions and macros that are use-
ful to UDF/TPF developers. The examples rely on
items in this file.
udf_utils.h A set of utility functions and macros that are use-
ful to UDF/TPF developers. The examples rely on
items in this file.
In general, a table UDF is always a producer of data. The server, however, may not always be
the consumer:
SELECT * FROM my_tpf( TABLE( SELECT * FROM my_table_udf() ) )
The outer TPF, my_tpf(), is the consumer for the table input parameter specified by
SELECT * from my_table_udf(). SAP Sybase IQ is the consumer of the table produced by the
my_tpf() TPF. A TPF, therefore, can be both a consumer and a producer.
The TPF does not have to consume from a table UDF. In this example, the TPF consumes the
table data produced by the inner query, which is produced by the SAP Sybase IQ server:
SELECT * FROM my_tpf( TABLE( SELECT * FROM my_table where my_table.c1
< 10 ) )
In a TPF, therefore, SAP Sybase IQ can be both the consumer and producer of table data.
In the v4 API, a row block defines a memory area where data is produced to, and consumed
from. In general, the layout of a row block conceptually matches the row and column format of
the table; a row block consists of a number of rows, and each row consists of a number of
columns. Either the producer or consumer must allocate the row block, and must also
deallocate it when the time comes.
Rows and column have their own specific attributes that only apply to them. For example,
rows have a status flag which indicates if the row is present or not. This flag lets a TPF change
the row status without having to move the column data. Columns have a null mask that
indicates if the data value is null or not. Row blocks also have some additional attributes:
maximum number of rows, and current number of rows, for example. These row block
attributes are useful when a UDF wants to create a row block to handle a large set of rows, but
produce a smaller number of rows as required.
The process of consuming a row is handled via one of the two fetch APIs:
• fetch_into
• fetch_block
The fetch_into is called when the consumer allocates the row block and passes it to the
producer. The producer is then requested to populate as many rows as possible, up to the
maximum number of rows. The fetch_block is called when the consumer wants the
producer to allocate the row block. Fetch_block is efficient if you are developing a TPF
that filters rows of data. The server (consumer) allocates the row block and fetches from the
TPF using the fetch_into API. The TPF can then pass the same row block to the input
parameter using the fetch_block API.
See also
• Row Block Data Exchange on page 128
static a_v4_extfn_table_udf_rg_table = {
&udf_table_funcs, // Table function descriptor
1 // number_of_columns
};
6. Implement the a_v4_extfn_proc structure functions.
The table UDF must provide an implementation for each of the a_v4_extfn_proc
functions that it declares in the a_v4_extfn_proc descriptor in step 3.
7. Implement the a_v4_extfn_table_func structure functions.
The table UDF must provide an implementation for each of the
a_v4_extfn_table_func functions that it declares in the
a_v4_extfn_table_func descriptor in step 5.
See also
• Scalar and Aggregate UDF Calling Patterns on page 82
• udf_rg_2 on page 111
• udf_rg_3 on page 115
• Implementing Sample Table UDF udf_rg_1 on page 106
• Table UDF Implementation Examples on page 105
• External Function (a_v4_extfn_proc) on page 288
• Table Functions (a_v4_extfn_table_func) on page 319
• _evaluate_extfn on page 290
See also
• Running the Sample Table UDF in udf_rg_1.cxx on page 111
• Running the Sample Table UDF in udf_rg_2.cxx on page 114
• Running the Sample Table UDF in udf_rg_3.cxx on page 118
To inform the server that this library contains v4 table UDFs, this function export is defined
in udf_main.cxx:
a_sql_uint32 SQL_CALLBACK extfn_use_new_api( void )
/*************************************************/
{
return EXTFN_V4_API;
}
3. Define the a_v4_extfn_proc descriptor.
This declares the necessary descriptor in udf_rg_1.cxx:
static a_v4_extfn_proc udf_rg_descriptor =
{
NULL, // _start_extfn
NULL, // _finish_extfn
udf_rg_evaluate, // _evaluate_extfn
udf_rg_describe, // _describe_extfn
NULL, // _leave_state_extfn
NULL, // _enter_state_extfn
NULL, // Reserved: must be NULL
NULL // Reserved: must be NULL
};
4. Define a library entry point function.
This callback function declares the main entry point function. It simply returns a pointer to
the a_v4_proc_descriptor variable udf_rg_descriptor.
extern "C"
a_v4_extfn_proc * SQL_CALLBACK udf_rg_1_proc()
/******************************************/
{
return &udf_rg_descriptor;
}
5. Define how the server gets row information from the table UDF.
This declares the a_v4_extfn_table_func descriptor that is used to tell the server
how to retrieve row data from the table UDF:
static a_v4_extfn_table_func udf_rg_table_funcs =
{
udf_rg_open, // _open_extfn
udf_rg_fetch_into, // _fetch_into_extfn
NULL, // _fetch_block_extfn
NULL, // _rewind_extfn
udf_rg_close, // _close_extfn
NULL, // Reserved: must be NULL
NULL // Reserved: must be NULL
};
In this example, the _fetch_into_extfn function transfers row data to the server.
This is the easiest data transfer method to understand and implement. This document refers
to data transfer methods as rowblock data exchange. There are two rowblock data
exchange functions: _fetch_into_extfn and _fetch_block_extfn.
At runtime, when the _evaluate_extfn function is called, the UDF publishes the
table functions descriptor by setting the result set parameter. To do this, the UDF must
create an instance of a_v4_extfn_table:
static a_v4_extfn_table udf_rg_table = {
&udf_rg_table_funcs, // Table function descriptor
1 // number_of_columns
};
The _evaluate_extfn method sends the server information about getting the result
set from the UDF. This is done by calling the a_v4_extfn_proc_context method
set_value on argument 0. Argument 0 represents the return value, which for a table
The open method first reads in the value of argument 1 using the a_v4_proc_context
method get_value. An instance of udf_rg_state is allocated using the
a_v4_proc_context function alloc. table UDFs should use the memory
management functions (alloc and free) on the a_v4_proc_context structure
whenever possible to manage their memory. The state object is then saved in the user_data
field of a_v4_proc_context. Memory stored in this field is available to the table
UDF until execution finishes.
static short UDF_CALLBACK udf_rg_open(
a_v4_extfn_table_context * tctx )
/***************************************/
{
an_extfn_value value;
return 0;
}
return 1;
}
The _fetch_info_extfn method returns row data to the server. This method is called
repeatedly until it returns false. For this example, the table UDF retrieves the state
information from the user_data field of the a_v4_extfn_proc_context object to
determine the next row to generate and the total number of rows to generate. This method is
free to generate up to the maximum number of rows indicated in the rowblock structure
passed in.
For this example, the table UDF generates a single column of type INT. It copies the data
for the next_row saved in the state into the data pointer of the first column. Each time
through the loop, the table UDF copies a new value into the data pointer and stops when
either the maximum number of rows to produce is reached or the row block is full.
static short UDF_CALLBACK udf_rg_fetch_into(
a_v4_extfn_table_context *tctx,
a_v4_extfn_row_block *rb)
/*******************************************/
{
udf_rg_state *state = (udf_rg_state *)tctx->user_data;
state->next_row++;
rb->num_rows++;
}
The table UDF calls the _close_extfn method once per new value for the parameters,
after all the rows have been fetched. In other words, for each _open_extfn call, there is
a subsequent _close_extfn call. In this example, the table UDF must free the memory
allocated during the _open_extfn call which it does by retrieving the state from the
user_data field of a_v4_extfn_proc_context object and calling the free method.
static short UDF_CALLBACK udf_rg_close(
a_v4_extfn_table_context *tctx)
/*************************************/
{
udf_rg_state * state = NULL;
return 1;
}
See also
• udf_rg_2 on page 111
• udf_rg_3 on page 115
• Row Block Data Exchange on page 128
• Describe API on page 208
• _evaluate_extfn on page 290
udf_rg_2
The sample table UDF udf_rg_2 builds on the sample in udf_rg_1.cxx and has the
same behavior. The procedure is called udf_rg_2 and its implementation is in the samples
directory in udf_rg_2.cxx.
The table UDF udf_rg_2 provides an alternate implementation of the _describe_extfn
method in the a_v4_extfn_proc descriptor.
static void UDF_CALLBACK udf_rg_describe(
a_v4_extfn_proc_context *ctx )
/*****************************************************************/
{
a_sql_int32 desc_rc;
EXTFNAPIV4_DESCRIBE_UDF_NUM_PARMS,
&num_parms,
sizeof( num_parms ) );
an_extfn_value p1_value;
a_v4_extfn_estimate num_rows;
( ctx,
1,
EXTFNAPIV4_DESCRIBE_PARM_CONSTANT_VALUE,
&p1_value,
sizeof( p1_value ) );
}
}
• EXTFNAPIV4_DESCRIBE_PARM_TYPE
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_COLUMNS
• EXTFNAPIV4_DESCRIBE_COL_TYPE
If the information set in these describe methods does not match the procedure definition
from the CREATE PROCEDURE statement, the describe_parameter_set and
describe_column_set methods return
EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE. The describe method then
sets an error to indicate to the client there is a mismatch.
This example uses the macro UDF_CHECK_DESCRIBE defined in udf_utils.h to check
the return value from a describe and set an error, if it is not successful.
During optimization, the udf_rg_2 table udf informs the server that it returns the same number
of rows indicated in parameter one. Since the generated rows increment, the values are also
unique. During optimization, only parameters that have a constant value are available. Use the
describe attribute EXTFNAPIV4_DESCRIBE_PARM_CONSTANT_VALUE to obtain
the value of a constant parameter. Once the table udf determines that the attribute value is
available, udf_rg_2 sets EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_ROWS and
EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES to the value obtained.
See also
• udf_rg_3 on page 115
• Implementing Sample Table UDF udf_rg_1 on page 106
IQ returns an error.
udf_rg_3
The sample table UDF udf_rg_3 builds upon udf_rg_2 and has similar behavior. The
procedure is called udf_rg_3 and its implementation is in the samples directory in
udf_rg_3.cxx.
The difference between the behavior of table UDFs udf_rg_3 and udf_rg_2 is that udf_rg_3
generates only 100 unique values from 0 to 99, then repeats the sequence as necessary. This
table UDF provides _start_extfn and _finish_extfn methods and has a modified
version of _describe_extfn to account for the different semantics of the function.
Using fetch_block instead of fetch_into allows the table UDF to own the row block
structure and use its own data layout. To illustrate this, the numbers generated are pre-
allocated in an array. When a fetch is performed, rather than copying data into the server
provided row block, the table UDF points the row block data pointers directly to the memory
containing the data, thus preventing additional copies.
The following ancillary structure stores the numbers array. This structure also keeps a pointer
to the allocated row block, which deallocates the row block.
#define MAX_ROWS 100
struct RowData {
a_sql_int32 numbers[MAX_ROWS];
a_sql_uint32 piece_len;
a_v4_extfn_row_block * rows;
void Init()
{
rows = NULL;
piece_len = sizeof( a_sql_int32 );
for( int i = 0; i < MAX_ROWS; i++ ) {
numbers[i] = i;
}
}
};
This structure is allocated when execution of the table UDF starts, and deallocated when
execution finishes, by providing _start_extfn and _finish_extfn methods in the
a_v4_extfn_proc_context.
static void UDF_CALLBACK udf_rg_start(
a_v4_extfn_proc_context *ctx )
/*************************************/
{
// The start_extfn method is a good place to allocate our row
// data. This method is called only once at the beginning of
// execution.
RowData *row_data = (RowData *)
ctx->alloc( ctx, sizeof( RowData ) );
row_data->Init();
ctx->_user_data = row_data;
}
(*rows)->num_rows = 0;
The first time this method is called, a row block is allocated using the helper function
BuildRowBlock, which is in udf_utils.cxx. A pointer to this row block is saved in the
RowData structure for later use.
Row generation is achieved by setting the data pointer for the column data to the address of the
next number in sequence in the previously allocated numbers array. The piece_len pointer
for the column data must also be initialized, by setting it to the address of the piece_len
member of RowData. Since the rows are a fixed data length, this number is the same for all
rows.
When fetch is called the last time and there is no more data to produce, the row block structure
is destroyed using the DestroyRowBlock helper function in udf_utils.cxx.
To accommodate this table UDF generating only 100 unique values,
EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES is set to a value of 100. This code
excerpt from the describe method demonstrates this:
static void UDF_CALLBACK udf_rg_describe(
a_v4_extfn_proc_context *ctx )
/*****************************************************************/
{
...
...
...
a_v4_extfn_estimate distinct = {
MAX_ROWS, 1.0
};
See also
• udf_rg_2 on page 111
• Implementing Sample Table UDF udf_rg_1 on page 106
apache_log_reader
The sample table UDF apache_log_reader reads the contents of an Apache access log
or an Apache error log into table data. It is implemented in the file
apache_log_reader.cxx in the samples directory.
A sample access log (apache_access.log) and sample error log
(apache_error.log) are included in the samples directory.
The apache_log_reader sample opens the log file in the _open_extfn method. It
reads in the data and parses it into the schema supported by the procedure in the
_fetch_into_extfn method. It then closes the log file using the _close_extfn
method.
See also
• _open_extfn on page 321
• _fetch_into_extfn on page 322
• _close_extfn on page 324
udf_blob
The sample table UDF udf_blob illustrates how a table UDF or TPF can read LOB input
parameters using the blob API.
udf_blob counts the number of occurrences of a letter in the first input parameter. The data
type of parameter 1 can be LONG VARCHAR or VARCHAR(64). If the type is LONG
VARCHAR, the table UDF uses the blob API to read in the value. If the type is
VARCHAR(64), the entire value is available using get_value.
This code snippett from the _open_extfn method illustrates how parameter 1 is read using
the blob API:
if( EXTFN_IS_INCOMPLETE(value) ) {
// If the value is incomplete, then that means we
// are dealing with a blob.
tctx->proc_context->get_blob( tctx->args_handle, 1, &blob );
return_value = ProcessBlob( tctx->proc_context,
blob,
letter_to_find );
blob->release( blob );
} else {
// The entire value was put into the value pointer.
return_value = CountNum( (char *)value.data,
value.piece_len,
letter_to_find );
}
…
…
}
Parameter 1 is retrieved using get_value. If the value is empty or NULL, then no further
processing is required. If the value is determined to be a blob using the macro
EXTFN_IS_INCOMPLETE, then the Table UDF gets an instance of a_v4_extfn_blob
using the get_blob method of a_v4_extfn_proc_context. The ProcessBlob
method reads from the blob to determine how many occurrences of the specified letter are
present.
See also
• Blob (a_v4_extfn_blob) on page 199
• _open_extfn on page 321
• get_blob on page 304
• External Procedure Context (a_v4_extfn_proc_context) on page 292
See also
• Generic describe_column Errors on page 325
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Set) on page 228
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Get) on page 211
Initial State
Initial state on the server. The only UDF method called during the Initial state is
_start_extfn.
The server calls the start method for each instance of the UDF created. If a query is executed by
a single server thread, then the start method is called once. If a query is handled by several
threads, or distributed across several nodes, the server creates different UDF instances and, as
a result, the start method is called several times.
UDFs can set function instance level data within the _user_data field of the
a_v4_extfn_proc_context structure, which is the argument to the start method.
Annotation State
During the annotation state the server updates the parse tree with the metadata necessary for
efficient and correct query optimization.
The [_enter_state], _describe_extfn, and [_leave_state] methods are
called. The _enter_state and _leave_state methods are optional and called if
provided by the UDF.
The annotation state is represented in the v4 API by EXTFNAPIV4_STATE_ANNOTATION
from the a_v4_extfn_state enumeration:
typedef enum a_v4_extfn_state {
… EXTFNAPIV4_STATE_ANNOTATION, …
} a_v4_extfn_state;
As a UDF developer, you can perform some initial schema negotiation in this phase. Schema
negotiation can occur either through the UDF describing to the server what it supports, or the
UDF asking the server how it was declared.
When the UDF describes itself to the server, the server detects mismatches and returns SQL
errors back to the client. For example, if a UDF describes that it requires four parameters and
the SQL writer only declared the UDF with two, the server detects this and returns a SQL error
back to the client.
When the UDF itself performs the validation by asking the server how it was declared, it
adjusts its runtime execution accordingly: it either matches the declaratio, or it returns an error
via the set_error v4 API. For example, assume you build a UDF that returns the maximum
value of up to five input scalar integers. At runtime, the UDF determines how many input
parameters were provided and adjusts its internal logic accordingly. SQL analysts could then
create the procedure as:
CREATE PROCEDURE my_sum_2( IN a INT, IN b INT ) EXTERNAL
"my_sum@my_lib"
CREATE PROCEDURE my_sum_3( IN a INT, IN b INT, IN c INT ) EXTERNAL
"my_sum@my_lib"
Both functions use the same underling implementation of my_sum. The UDF recognizes that
there are only two parameters for my_sum_2, and attempts to sum parameters 1 and 2. For
my_sum_3, the UDF sums parameters 1, 2 and 3.
As a UDF developer, you can obtain values for constant literal parameters only in the
Annotation state. No other values are available until the Execution state. To get parameter
values during the annotation state use the describe_parameter_get method with the
PARM_CONSTANT_VALUE and PARM_IS_CONSTANT attributes.
In the Annotation state, UDFs have access to schema describe attributes:
• EXTFNAPIV4_DESCRIBE_UDF_NUM_PARMS
• EXTFNAPIV4_DESCRIBE_PARM_NAME
• EXTFNAPIV4_DESCRIBE_PARM_TYPE
• EXTFNAPIV4_DESCRIBE_PARM_WIDTH
• EXTFNAPIV4_DESCRIBE_PARM_SCALE
• EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT
• EXTFNAPIV4_DESCRIBE_PARM_CONSTANT_VALUE
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_COLUMNS
• EXTFNAPIV4_DESCRIBE_COL_NAME
• EXTFNAPIV4_DESCRIBE_COL_TYPE
• EXTFNAPIV4_DESCRIBE_COL_WIDTH
• EXTFNAPIV4_DESCRIBE_COL_SCALE
• EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT
• EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE
During the Annotation phase the UDF can set the above values to define its schema to the
server. If the server detects a mismatch between what the UDF describes and the SQL
procedure declaration, it returns an error. This technique is referred to as self-describing.
An alternative technique, schema validation, can be employed by the UDF. This involves the
UDF getting the values for the schema describe types, and then setting an error if a mismatch is
detected. With this approach, validation is left to the UDF, but the UDF can choose to support
multiple schemas with a single implementation (for example, the ability to support multiple
datatypes for a given parameter or being able to support varying number of parameters).
See also
• EXTFNAPIV4_DESCRIBE_UDF_NUM_PARMS Attribute (Get) on page 278
• EXTFNAPIV4_DESCRIBE_UDF_NUM_PARMS Attribute (Set) on page 280
• EXTFNAPIV4_DESCRIBE_PARM_NAME Attribute (Get) on page 243
• EXTFNAPIV4_DESCRIBE_PARM_NAME Attribute (Set) on page 262
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Get) on page 244
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Set) on page 263
• EXTFNAPIV4_DESCRIBE_PARM_WIDTH Attribute (Get) on page 245
• EXTFNAPIV4_DESCRIBE_PARM_WIDTH Attribute (Set) on page 264
• EXTFNAPIV4_DESCRIBE_PARM_SCALE Attribute (Get) on page 246
• EXTFNAPIV4_DESCRIBE_PARM_SCALE Attribute (Set) on page 265
• EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT Attribute (Get) on page 251
• EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT Attribute (Set) on page 267
See also
• DEFAULT_TABLE_UDF_ROW_COUNT Option on page 179
• EXTFNAPIV4_DESCRIBE_PARM_NAME Attribute (Get) on page 243
• EXTFNAPIV4_DESCRIBE_PARM_NAME Attribute (Set) on page 262
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Get) on page 244
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Set) on page 263
• EXTFNAPIV4_DESCRIBE_PARM_WIDTH Attribute (Get) on page 245
• EXTFNAPIV4_DESCRIBE_PARM_WIDTH Attribute (Set) on page 264
• EXTFNAPIV4_DESCRIBE_PARM_SCALE Attribute (Get) on page 246
• EXTFNAPIV4_DESCRIBE_PARM_SCALE Attribute (Set) on page 265
• EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT Attribute (Get) on page 251
At this point in query processing, the server determines what columns are needed from the
UDF, and requests information about the columns needed from the TABLE parameters.
If the UDF supports parallel processing, and if the server agrees that the query is eligible for
parallelism, the server creates multiple instances of the UDF for distributed query processing.
In the Plan Building state, UDFs have access to all describe attributes.
As an example, the following code fragment queries the server to determine which columns
are used:
a_sql_int32 rc;
rg_udf *rgUdf = (rg_udf *)ctx->_user_data;
rg_table *rgTable = rgUdf->rgTable;
a_sql_uint32 buffer_size = 0;
rc = ctx->describe_parameter_get( ctx,
0,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS,
ulist,
buffer_size );
if( rc != buffer_size ) {
Assuming the above code fragment is from a Table UDF that produces 4 result set columns,
and assuming the SQL statement was
SELECT c1, c2 FROM my_table_proc();
then the describe API returns only c1 and c2. This lets the UDF optimize the production of
the result set values.
See also
• Describe API on page 208
Execution State
During the execution state, the server makes an execution call into the UDF.
The execution plan, created in the plan building state, is used in the execution state to compute
the result set of the SQL query.
These methods can be called: [_enter_state], _describe_extfn,
evaluate_extfn, _open_extfn, _fetch_into_extfn,
_fetch_block_extfn, _close_extfn, [_leave_state], and
_finish_extfn.
The execution state is represented in the a_v4_extfn_state API by this enumeration:
typedef enum a_v4_extfn_state {
… EXTFNAPIV4_STATE_EXECUTING, …
} a_v4_extfn_state;
A TPF can both produce and consume rows. A TPF produces rows in the same way a table
UDF produces rows and can use an existing row block or build its own row block. A TPF can
consume rows from an input table and can provide the producer with a row block, or request
the producer to create its own row block.
See also
• Row Block (a_v4_extfn_row_block) on page 309
• Table (a_v4_extfn_table) on page 310
• Table Functions (a_v4_extfn_table_func) on page 319
• _open_extfn on page 321
• _fetch_into_extfn on page 322
• _fetch_block_extfn on page 322
• _rewind_extfn on page 323
• _close_extfn on page 324
See also
• Table Parameterized Functions on page 136
• fetch_into on page 313
• fetch_block on page 316
See also
• Using a Row Block to Produce Data on page 131
• fetch_block on page 316
This API enables consumers to optionally construct the row block, such that the data pointers
refer to its own data structures. This allows the producer to directly populate memory within
the consumer. A consumer may not want to do this, if data cleansing or validation checks are
required first.
Fetch is executed against a table object, which is either the object produced as the result set of a
table UDF or the object consumed as a result set of an input TABLE parameter.
See also
• Using a Row Block to Produce Data on page 131
• fetch_into on page 313
See also
• Table UDF Implementation Examples on page 105
• fetch_into on page 313
• fetch_block on page 316
• Row Block (a_v4_extfn_row_block) on page 309
• Row (a_v4_extfn_row) on page 309
• Column Data (a_v4_extfn_column_data) on page 204
1. Set num_rows to a value based on the number of rows produced in the fetch call.
2. For each row produced, set the row_status flag of a_v4_extfn_row to 1 (available)
or 0 (not available). The default value is 1.
3. For each column (a_v4_extfn_column_data) in the row set:
Options Description
is_null Set to true, if the value returned is NULL. The default is false.
Options Description
data The data returned must be copied into this pointer
piece_len The actual length of data returned. For fixed-length data types, this cannot
exceed max_piece_len. Defaults to max_piece_len for fixed data types.
4. For each column, return 1 to indicate rows produced, and return 0 to indicate otherwise.
1. Set max_rows to the number of rows the producer-allocated row block structure can
hold.
2. On the first fetch call, allocate a row block structure that can hold max_rows.
3. Set num_rows to a value based on the number of rows produced in the fetch call.
4. For each row produced, set the row_status flag of a_v4_extfn_row to 1 (available)
or 0 (not available). The default value is 1.
5. For each column (a_v4_extfn_column_data) in the row set:
data Set this pointer to the area in the producer's memory containing the data to
be returned.
piece_len The actual length of data being returned. For fixed-length data types, this
cannot exceed max_piece_len. This value defaults to max_piece_len for
fixed data types.
6. Return 1 from fetch_into to indicate rows were produced, and return 0 to indicate
otherwise. On the last fetch call, deallocate any memory that is allocated for the row block
structure.
These relevant data structures in the extfnapiv4.h header file are used when allocating a
row block:
typedef struct a_v4_extfn_column_data {
a_sql_byte *is_null;
a_sql_byte null_mask;
a_sql_byte null_value;
void *data;
a_sql_uint32 *piece_len;
size_t max_piece_len;
void *blob_handle;
} a_v4_extfn_column_data;
When allocating a row block, the developer must decide how many rows the row block is
capable of holding, how many columns each row has, and the number of bytes required for
each of those columns.
For a row block of size m, where each row has n columns, the developer must allocate an array
of m a_v4_extfn_row structures. For each row in this array, the developer must allocate n
a_v4_extfn_column_data structures.
These tables outline allocation requirements for each member of the row block structures:
Field Requirement
*column_data Allocate an array containing the number of col-
umns in the result set of a_v4_extfn_col-
umn_data structures
See also
• SQL Data Types on page 9
• External Procedure Context (a_v4_extfn_proc_context) on page 292
• ORDER BY node (TPF only) – for a TPF, the query plan shows an ORDER BY node as a
child of the TPF SubQuery node. The ORDER BY node indicates that the data is ordered
as it flows into the TABLE parameter.
• Output Row Width – (visible only if the UDF is using _fetch_into_extfn.) Shows
the width of an output column in bytes. This value is used in calculating the maximum
number of rows.
• TableUDF node – represents an instance of a table UDF in the query. The TableUDF node
is a leaf node.
• TPF node (TPF only) – same as the TableUDF node except that TPF node permits use of
an input TABLE parameter. Unlike a TableUDF node which is a leaf node, the TPF is an
interior node with at most one child.
• TPF SubQuery node (TPF only) – child of the TPF node. Represents the subquery for the
input table argument.
• UDF Library – UDF library file name. Shows the full path on disk from which the
dynamic library implementing the UDF was loaded.
• Uniqueness of an output column – reflects the value set by
extfnapiv4_describe_col_is_unique.
• TABLE_UDF_ROW_BLOCK_SIZE_KB – option value displays in query plan
statistics if you specify a value other than 128KB.
See also
• alloc on page 301
• free on page 302
Task See
Familiarize yourself with table UDF develop- Learning Roadmap for Table UDF Developers on
ment. page 97
Follow the recommended procedure for creating Developing a TPF on page 136
a TPF.
TPF Implementation Examples on page 156
Establish a table context for the input table and Consume TABLE Parameters on page 137
consume table rows from it.
(Optional) Order incoming data. Order Input Table Data on page 140
(Optional) Partition the incoming data to enable Partitioning Input Data on page 140
parallel TPF processing in your multiplex.
Developing a TPF
Review the major steps required to develop a TPF.
See also
• Consume TABLE Parameters on page 137
• Order Input Table Data on page 140
• Partitioning Input Data on page 140
• _open_extfn on page 321
• _fetch_into_extfn on page 322
• _fetch_block_extfn on page 322
• _rewind_extfn on page 323
• _evaluate_extfn on page 290
• Developing a Table UDF on page 103
a_v4_extfn_value value;
a_v4_extfn_table * table;
ctx->get_value( args_handle,
1,
&value );
See also
• get_value on page 294
a_v4_extfn_table_context * rs = NULL;
ctx->open_result_set( ctx,
(a_v4_extfn_table *)value.data,
&rs ) );
See also
• open_result_set on page 303
• Table Context (a_v4_extfn_table_context) on page 311
See also
• fetch_into on page 313
• fetch_block on page 316
• Row Block Data Exchange on page 128
See also
• Column Data (a_v4_extfn_column_data) on page 204
• Row Block (a_v4_extfn_row_block) on page 309
• Row (a_v4_extfn_row) on page 309
• get_blob on page 318
ctx->close_result_set( ctx,
rs ) );
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_ORDERBY Attribute (Get) on page 255
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_ORDERBY Attribute (Set) on page 270
See also
• Parallel TPF PARTITION BY Examples Using
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY on page 143
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY (Get) on page 256
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY (Set) on page 272
• V4 API describe_parameter and
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY on page 141
Declaration
The describe_parameter API has two declarations.
describe_parameter_set Declaration
a_sql_int32 (SQL_CALLBACK *describe_parameter_set)(
a_v4_extfn_proc_context *cntxt,
a_sql_uint32 arg_num,
a_v4_extfn_describe_parm_type describe_type,
void *describe_buffer,
size_t describe_buffer_
)
describe_parameter_get Declaration
a_sql_int32 (SQL_CALLBACK *describe_parameter_get)(
a_v4_extfn_proc_context *cntxt,
a_sql_uint32 arg_num,
a_v4_extfn_describe_parm_type describe_type,
const void *describe_buffer,
size_t describe_buffer_
)
Usage
In order to use these APIs, the arg_num must refer to a TABLE parameter, and the
describe_buffer must refer to the type of memory block a_v4_extfn_column_list
structure.
typedef struct a_v4_extfn_column_list {
a_sql_int32 number_of_columns;
a_sql_uint32 column_indexes[1];
} a_v4_extfn_column_list;
describe_parameter_set Scenarios
{0} UDF can support any form of input table partitioning as per UDF request.
describe_parameter_get Scenarios
See also
• Describe API on page 208
• Partition By Column Number (a_v4_extfn_partitionby_col_num) on page 307
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Get) on page 244
See also
• Partitioning Input Data on page 140
See also
• describe_parameter_set Example # 1: One-Column Partitioning on Column 1 on page
144
• describe_parameter_set Example # 2: Two-Column Partitioning on page 146
• describe_parameter_set Example # 3: Any-Column Partitioning on page 148
• describe_parameter_set Example # 4: No Support for PARTITION BY ANY Clause on
page 150
if( rc == 0 ) {
ctx->set_error( ctx, 17000,
“Runtime error, unable set partitioning requirements for
column.” );
}
}
}
See also
• Example Procedure Definition on page 143
• describe_parameter_set Example # 2: Two-Column Partitioning on page 146
• describe_parameter_set Example # 3: Any-Column Partitioning on page 148
• describe_parameter_set Example # 4: No Support for PARTITION BY ANY Clause on
page 150
• describe_parameter_set Example # 5: No Partitioning Support on page 151
• describe_parameter_set Example # 6: One-Column Partitioning on Column 2 on page
153
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.x ) )
In this example, the UDF describes to the server that the data is partitioned by the first column
(T.x) and the SQL writer also explicitly requests partitioning on the same column. When the
two columns match, the above query proceeds without any errors using this negotiated query:
my_tpf( TABLE( SELECT T.x, T.y FROM T )
OVER ( PARTITION BY T.x ) )
V4 describe_parameter_get API returns: { 1, 1 }
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY ANY ) )
In this example, the UDF describes to the server that the data is partitioned by the first column
(T.x) and the SQL writer only wants the query engine to execute the UDF on partitions. The
server uses the UDF's preference for partitioning and as a result the same effective query in
Example 1 is executed.
Example 3
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T ) )
This example shows that the SQL writer does not include the PARTITION BY clause or the
PARTITION BY DEFAULT clause as part of the input table query specification. In this case, the
specification requested by the UDF applies, which is to perform partitioning on column T.x.
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.y ))
In this example the UDF describes to the server that the data is partitioned by the first column
(T.x) and that the SQL writer is also explicitly requesting partitioning on a different column
(T.y) which conflicts with what the UDF is requesting and as a result the server returns a SQL
error.
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( NO PARTITION BY ))
This example conflicts with the request made by the UDF because the SQL writer does not
want the input table partitioned and as a result the server returns a SQL error.
Example 3
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.x, T.y ))
In this example the UDF describes to the server that the data is partitioned by the first column
(T.x) and the SQL writer requests partitioning on columns (T.x and T.y) which conflicts with
what the UDF is requesting and as a result the server returns a SQL error.
if( rc == 0 ) {
ctx->set_error( ctx, 17000,
“Runtime error, unable set partitioning requirements for
column.” );
}
}
}
See also
• Example Procedure Definition on page 143
• describe_parameter_set Example # 1: One-Column Partitioning on Column 1 on page
144
• describe_parameter_set Example # 3: Any-Column Partitioning on page 148
• describe_parameter_set Example # 4: No Support for PARTITION BY ANY Clause on
page 150
• describe_parameter_set Example # 5: No Partitioning Support on page 151
• describe_parameter_set Example # 6: One-Column Partitioning on Column 2 on page
153
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.y, T.x ))
In this example, the UDF describes to the server that the data is partitioned by columns T.y and
T.x. The SQL writer also requests partitioning on the same column. When the two columns
match, the above query proceeds without any errors using this negotiated query:
my_tpf( TABLE( SELECT T.x, T.y FROM T )
OVER ( PARTITION BY T.y, T.x ) )
V4 describe_parameter_get API returns: { 2, 2, 1 }
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY ANY ))
In this example, the SQL writer does not specify a specific column for partitioning. Instead the
SQL writer partitions the input table. The UDF requests partitioning on columns T.y and T.x,
and as a result, the server partitions the input data on the columns T.y and T.x.
Example 3
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
This example shows that the SQL writer does not include PARTITION BY clause or the
PARTITION BY DEFAULT clause. The server uses the partition requested by the UDF, and since
the UDF describes that it requires partitioning on columns T.y and T.x, the server executes the
query by performing partitioning on columns T.y and T.x.
Example 4
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.x,T.y))
This example is semantically identical to Example 1. The ordering of the two columns are
different, but within a given partition, the values for columns T.x and T.y stay the same. Both
columns (T.x, T.y) and columns (T.y, T.x) result in the same logical partitioning of data.
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( NO PARTITION BY ) )
This example conflicts with the request made by the UDF because the SQL writer does not
want the input table partitioned. As a result, the server returns a SQL error.
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.x ) )
In this example the UDF describes to the server that the data is partitioned by columns T.y and
T.x, while the SQL writer requests the partitioning on either column T.y or T.x. which conflicts
with what the UDF is requesting. As a result, the server returns a SQL error.
if( rc == 0 ) {
ctx->set_error( ctx, 17000,
“Runtime error, unable set partitioning requirements for
column.” );
}
}
}
See also
• Example Procedure Definition on page 143
• describe_parameter_set Example # 1: One-Column Partitioning on Column 1 on page
144
• describe_parameter_set Example # 2: Two-Column Partitioning on page 146
• describe_parameter_set Example # 4: No Support for PARTITION BY ANY Clause on
page 150
• describe_parameter_set Example # 5: No Partitioning Support on page 151
• describe_parameter_set Example # 6: One-Column Partitioning on Column 2 on page
153
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.x ) )
In this example, the UDF describes to the server that the data is partitioned by the first column
(T.x) and the SQL writer also explicitly requests partitioning on the same column. When the
two columns match, the above query proceeds without any errors using this negotiated query:
my_tpf( TABLE( SELECT T.x, T.y FROM T )
OVER ( PARTITION BY T.y, T.x ) )
V4 describe_parameter_get API returns: { 2, 2, 1 }
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY ANY ) )
In this example, nether the SQL writer nor the UDF specify a specific column for partitioning.
Iinstead the SQL writer partitions the input table and, as a result, the server arranges
partitioning in a nonvalue-based scheme and the data is partitioned over ranges of rows.
See also
• Example Procedure Definition on page 143
• describe_parameter_set Example # 1: One-Column Partitioning on Column 1 on page
144
• describe_parameter_set Example # 2: Two-Column Partitioning on page 146
• describe_parameter_set Example # 3: Any-Column Partitioning on page 148
• describe_parameter_set Example # 5: No Partitioning Support on page 151
• describe_parameter_set Example # 6: One-Column Partitioning on Column 2 on page
153
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T ))
This example shows that the SQL writer does not include PARTITION BY clause. The server
uses the partition requested by the UDF and since the UDF does not supports any partitioning
requirements, the server executes the query without performing any partitioning.
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( NO PARTITION BY ))
In this example, the SQL writer requests the NO PARTITION BY clause as part of the input table
query specification. As a result, the server executes the query with no runtime partitioning.
Example 3
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
In this example the UDF does not describe any partitioning requirements. However, the SQL
writer requests partitioning by column T.x and as a result the server executes the query by
performing partitioning on column T.x.
Example 4
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.y))
In this example, the UDF does not describe any partitioning requirements. However, the SQL
writer requests partitioning by column T.y. As a result, the server executes the query by
performing partitioning on column T.y.
Example 5
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.y, T.x))
In this example, the UDF does not describe any partitioning requirements. However, the SQL
writer requests partitioning by columns T.y and T.x. As a result, the server executes the query
by performing partitioning on columns T.y and T.x.
Example 6
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY ANY ))
In this example, the SQL writer requests PARTITION BY ANY partitioning. However, the UDF
does not support any partitioning requirements. As a result, the server executes the query by
performing row range partitioning.
ctx,
1,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY,
&pbcol,
sizeof(pbcol) );
if( rc == 0 ) {
ctx->set_error( ctx, 17000,
“Runtime error, unable set partitioning requirements for
column.” );
}
}
}
See also
• Example Procedure Definition on page 143
• describe_parameter_set Example # 1: One-Column Partitioning on Column 1 on page
144
• describe_parameter_set Example # 2: Two-Column Partitioning on page 146
• describe_parameter_set Example # 3: Any-Column Partitioning on page 148
• describe_parameter_set Example # 4: No Support for PARTITION BY ANY Clause on
page 150
• describe_parameter_set Example # 6: One-Column Partitioning on Column 2 on page
153
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY ANY )
In this example, the SQL writer requests PARTITION BY ANY partitioning. However, the UDF
does not support any partitioning, and as a result, the server executes the query without
runtime partitioning.
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
This example shows that the SQL writer does not include the PARTITION BY clause or the
PARTITION BY DEFAULT clause. The server uses the partition requested by the UDF and since
the UDF does not supports any partitioning, the server executes the query without performing
any partitioning.
Example 3
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( NO PARTITION BY )
In this example, the SQL writer requests no partitioning, and as a result, the server executes the
query without runtime partitioning.
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.x ))
This example results in a SQL error because the SQL writer requested partitioning on column
T.x, and the UDF does not support any partitioning on any columns.
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.y ))
This example results in a SQL error because the SQL writer requested partitioning on column
T.y, and the UDF does not support any partitioning on any columns.
Example 3
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.y, T.x ))
This example results in a SQL error because the SQL writer requested partitioning on columns
T.y and T.x, and the UDF does not support any partitioning on any columns.
if( rc == 0 ) {
ctx->set_error( ctx, 17000,
“Runtime error, unable set partitioning requirements for
column.” );
}
}
}
See also
• Example Procedure Definition on page 143
• describe_parameter_set Example # 1: One-Column Partitioning on Column 1 on page
144
• describe_parameter_set Example # 2: Two-Column Partitioning on page 146
• describe_parameter_set Example # 3: Any-Column Partitioning on page 148
• describe_parameter_set Example # 4: No Support for PARTITION BY ANY Clause on
page 150
• describe_parameter_set Example # 5: No Partitioning Support on page 151
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.y )
In this example, the UDF describes to the server that the data is partitioned by the first column
(T.y), and the SQL writer also explicitly requests partitioning on the same column. When the
two columns match, the above query proceeds without any errors using this negotiated query:
my_tpf( TABLE( SELECT T.x, T.y FROM T )
OVER ( PARTITION BY T.y ) )
V4 describe_parameter_get API returns: { 1, 2 }
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY ANY )
In this example the SQL writer does not specify a specific column for partitioning. Instead the
SQL writer partitions the input table. The UDF requests partitioning on column T.y, and as a
result, the server partitions the input data on the column T.y.
Example 3
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
This example shows that the SQL writer does not include the PARTITION BY clause or the
PARTITION BY DEFAULT clause as part of the input table query specification. In this case, the
specification requested by the UDF applies, which is to perform partitioning on column T.y.
Example 1
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.x )
In this example, the UDF describes to the server that the data is partitioned by the first column
(T.y) ,and that the SQL writer is also explicitly requesting partitioning on a different column
(T.x), which conflicts with what the UDF is requesting. As a result the server returns a SQL
error.
Example 2
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( NO PARTITION BY )
This example conflicts with the request made by the UDF because the SQL writer does not
want the input table partitioned. As a result the server returns a SQL error.
Example 3
SELECT * FROM my_tpf(
TABLE( SELECT T.x, T.y FROM T )
OVER( PARTITION BY T.x, T.y )
In this example, the UDF describes to the server that the data is partitioned by the first column
(T.y), and the SQL writer requests partitioning on columns (T.x and T.y), which conflicts with
what the UDF is requesting. As a result the server returns a SQL error.
tpf_rg_1
TPF sample tpf_rg_1.cxx is similar to the table UDF sample udf_rg_2.cxx. It
produces rows of data based on an input parameter.
The number of rows generated is the sum of the values of the rows in a single input table. The
output is the same as udf_rg_2.cxx.
The majority of the code for this sample is the same as udf_rg_2.cxx. The main
differences are:
• The names of the implementing functions have the prefix tpf_rg instead of udf_rg.
See the file tpf_rg_1.cxx for details.
• The implementation of _describe_extfn validates the schema of this example but
does not estimate the number of rows generated.
• The implementation of _open_extfn reads rows from an input table to determine the
number of rows to generate.
The _describe_extfn method accommodates the schema differences between
udf_rg_2.cxx and this example. In particular, parameter 1 is a table with one integer
column. This code snippet illustrates _describe_extfn:
static void UDF_CALLBACK tpf_rg_describe(
a_v4_extfn_proc_context *ctx )
/****************************************/
{
a_sql_int32 desc_rc;
…
…
( ctx,
1,
EXTFNAPIV4_DESCRIBE_PARM_TYPE,
&type,
sizeof( type ) );
// Inform the server that the input table should have a single
// column.
num_cols = 1;
desc_rc = ctx->describe_parameter_set
( ctx,
1,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_COLUMNS,
&num_cols,
sizeof( num_cols ) );
…
…
}
}
In udf_rg_2.cxx, the number of rows generated by the UDF may be available during the
describe phase if the value is a constant. A table argument can never be constant, so its value is
unavailable until the Execution state. For this reason, no optimizer estimate for the number of
rows being generated is provided during the describe phase.
Calls to the describe only during the Annotation state have an effect in this example. Such calls
will do nothing in the other states.
The _open_extfn method reads in rows from the input table and sums their values. As in
the udf_rg_2.cxx example, the value of the first input parameter is retrieved using
get_value. The difference here is that the type of the parameter is a_v4_extfn_table
pointer. This code snippet illustrates _open_extfn:
static short UDF_CALLBACK tpf_rg_open(
a_v4_extfn_table_context * tctx )
/***************************************/
{
an_extfn_value value;
tpf_rg_state * state = NULL;
a_v4_extfn_table_context * rs = NULL;
a_sql_uint32 num_to_generate = 0;
return 0;
}
return 0;
}
return 0;
}
return 1;
}
Once you retrieve the table object using get_value, call open_result_set to read in
rows of data from the table.
To read rows from the input table, the UDF can use fetch_into or fetch_block. When
a UDF is fetching rows from an input table, it becomes a consumer of data. If the consumer
(the UDF in this case) wants to be responsible for managing the row block structure, then the
consumer must allocate their own row block structure and use fetch_into to retrieve the
data. Alternatively, if the consumer wants the producer (the server in this case) to manage the
row block structure, then use fetch_block. tpf_rg_1 demonstrates the latter.
Using an open result set, tpf_rg_1 retrieves rows of data from the server by calling
fetch_block repeatedly. Each successful call to fetch_block populates the server
allocated row block structure with up to num_rows rows. In tpf_rg_1, the value of
column 1 for each row is added to a total. As in the udf_rg_2.cxx example, this total is
saved in the a_v4_extfn_proc_context state to be used later.
See also
• Describe API on page 208
• _open_extfn on page 321
• Table (a_v4_extfn_table) on page 310
• _fetch_block_extfn on page 322
a) To see how the describe affects the behavior, issue a CREATE PROCEDURE
statement that has a different schema than the schema the TPF publishes in the
describe:
CREATE OR REPLACE PROCEDURE tpf_rg_1( IN tab TABLE( num INT,
num2 INT ) )
RESULT( c1 INT )
EXTERNAL NAME 'tpf_rg_1@libv4apiex';
b) Select rows from the TPF:
// This will return an error that the number of columns in
select list
does not match input table param schema
SELECT * from tpf_rg_1( TABLE( select val from test_table ) );
tpf_rg_2
TPF sample tpf_rg_2.cxx builds on the sample in tpf_rg_1.cxx and has similar
behavior. It produces rows of data based on an input parameter.
This sample provides an alternate implementation of the _open_extfn method in the
a_v4_extfn_func descriptor. The behavior is the same as tpf_rg_1 but the TPF uses
fetch_into instead of fetch_block to read rows from the input table.
This code snippet from the _open_extfn method shows fetch_into retrieving rows
from the input table:
a_sql_uint32 c1_data;
a_sql_byte c1_null = 0x0;
a_sql_uint32 c1_len = 0;
a_sql_byte null_mask = 0x1;
a_sql_byte null_value = 0x1;
a_v4_extfn_column_data cd[1] =
{
{ &c1_null, // is_null
null_mask, // null_mask
null_value, // null_value
&c1_data, // data
&c1_len, // piece_len
sizeof(c1_data), // max_piece_len
NULL // blob
}
};
a_sql_uint32 r_status;
a_v4_extfn_row row =
{
&r_status, &cd[0]
};
a_v4_extfn_row_block rb =
{
1, 0, &row
};
// Only consider non-null rows. They way the column data has
// been defined allows us to treat c1_null as a boolean.
if( !c1_null ) {
num_to_generate += c1_data;
}
…
…
}
When using fetch_into to retrieve rows from an input table, the TPF manages the row
block structure. In this example, a static row block structure is created that retrieves one row at
a time. Alternatively, you can allocate a dynamic structure that simultaneously supports an
arbitrary number of rows.
In the code snippet, the row block structure defined to store the value of the column from the
input table in the variable c1_data. If a NULL row is encountered, the variable c1_null is set to
1 to indicate this.
See also
• _open_extfn on page 321
• _fetch_into_extfn on page 322
The table test_table has three rows with values 1,2,3. The sum of these values is 6. The
example generates 6 rows.
The procedure supports multiple schemas. The data types for column s in the result set and
input table can be one of VARCHAR, BINARY, LONG VARCHAR, or LONG BINARY.
See also
• External Procedure Context (a_v4_extfn_proc_context) on page 292
• *describe_column_get on page 209
UDF_SQLERROR_RT( tctx->proc_context,
"Failed to get blob",
(ret == 1 && blob != NULL),
0 );
}
ret = blob->release( blob );
UDF_SQLERROR_RT( tctx->proc_context,
"Failed to release blob",
(ret == 1),
0 );
} else {
if( state->data_type == DT_VARCHAR ||
state->data_type == DT_LONGVARCHAR ) {
num = CountNum( (char *)cd[1].data,
*(cd[1].piece_len),
state>pattern );
} else {
char i = (char)atoi( &(state->pattern) );
num = CountNum( (char *)cd[1].data, *(cd[1].piece_len), i );
}
}
For each of the rows in the input table, the TPF checks if it is a blob using the macro
EXTFN_COL_IS_BLOB. If it is a blob, then the TPF uses the get_blob method of
a_v4_extfn_table_context to create a blob object for the specified column. On
success, the get_blob method provides the TPF with an instance of a_v4_extfn_blob,
which allows the TPF to read in the blob data. Once the TPF is finished with the blob, it should
call release on it.
The ProcessBlob method illustrates how a blob object processes the data:
static a_sql_uint64 ProcessBlob(
a_v4_extfn_proc_context *ctx,
a_v4_extfn_blob *blob,
char pattern)
/*******************************/
{
char buffer[BLOB_ISTREAM_BUFFER_LEN];
size_t len = 0;
short ret = 0;
a_sql_uint64 num = 0;
for(;;) {
len = is->get( is, buffer, BLOB_ISTREAM_BUFFER_LEN );
if( len == 0 ) {
break;
}
num += CountNum( buffer, len, pattern );
}
See also
• Blob Input Stream (a_v4_extfn_blob_istream) on page 203
• Blob (a_v4_extfn_blob) on page 199
• get_blob on page 318
• fetch_into on page 313
1. During the describe phase, ensure the TPF uses the describe_column_set method
of EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT to inform the
server that specific result-set rows are a subset of rows from an input table.
This code snippet from the describe_extfn method illustrates filtering:
else if( ctx->current_state == EXTFNAPIV4_STATE_OPTIMIZATION ) {
// The output columns of this TPF are the same as the first
// argument's input table columns. The following describe
// informs the consumer of this fact.
a_v4_extfn_col_subset_of_input colMap;
2. Pass the call to fetch_into for the input table the same rowblock structure that was
passed into the fetch_into_extfn method. This ensures that the rowblock structure
for the result set is the same as for the input tables.
See also
• EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT (Set) on page
240
• fetch_into on page 313
• _fetch_into_extfn on page 322
The table test_table has three rows with an even number of as. Row 1 has 10, row 3 has 12,
and row 5 has 14.
Syntax
Syntax 1
ALTER PROCEDURE [ owner.]procedure-name procedure-definition
Syntax 2
ALTER PROCEDURE [ owner.]procedure-name
REPLICATE { ON | OFF }
Syntax 3
ALTER PROCEDURE [ owner.]procedure-name
SET HIDDEN
Syntax 4
ALTER PROCEDURE [ owner.]procedure-name
RECOMPILE
Syntax 5
ALTER PROCEDURE
[ owner.]procedure-name ( [ parameter, …] )
[ RESULT (result-column, ...)]
EXTERNAL NAME ‘external-call’ [ LANGUAGE JAVA [ environment-name ] }
Parameters
(back to top) on page 167
• procedure-definition – CREATE PROCEDURE syntax following the name.
Usage
(back to top) on page 167
The ALTER PROCEDURE statement must include the entire new procedure. You can use
PROC as a synonym for PROCEDURE. Both Watcom and Transact-SQL® dialect procedures
can be altered through the use of ALTER PROCEDURE. Existing permissions on the procedure
are not changed. If you execute DROP PROCEDURE followed by CREATE PROCEDURE,
execute permissions are reassigned.
You cannot combine Syntax 2 with Syntax 1.
When using the ALTER PROCEDURE statement for table UDFs, the same set of restrictions
apply as for the CREATE PROCEDURE Statement (External Procedures).
Standards
(back to top) on page 167
Permissions
(back to top) on page 167
Alter a Watcom-SQL or Transcat-SQL procedure – Requires one of:
• ALTER ANY PROCEDURE system privilege.
• ALTER ANY OBJECT system privilege.
• You own the procedure.
Alter an external C/C++ or external environment procedure – Requires CREATE
EXTERNAL REFERENCE system privilege. Also requires one of:
• ALTER ANY PROCEDURE system privilege.
• ALTER ANY OBJECT system privilege.
• You own the procedure.
See also
• Table UDF Restrictions on page 99
• CREATE PROCEDURE Statement (Table UDF) on page 169
Quick Links:
Go to Parameters on page 170
Go to Usage on page 171
Go to Standards on page 172
Go to Permissions on page 172
Syntax
CREATE[ OR REPLACE ] PROCEDURE
[ owner.]procedure-name ( [ parameter[, …]] )
| RESULT result-column [, …] )
[ SQL SECURITY { INVOKER | DEFINER } ]
EXTERNAL NAME ‘external-call’
Parameters
(back to top) on page 169
• IN – the parameter is an object that provides a value for a scalar parameter or a set of values
for a TABLE parameter to the UDF.
Note: TABLE parameters cannot be declared as INOUT or OUT. You can only have one
TABLE parameter (the position of which is not important).
• OR REPLACE – specifying OR REPLACE (CREATE OR REPLACE PROCEDURE)
creates a new procedure, or replaces an existing procedure with the same name. This
clause changes the definition of the procedure, but preserves existing permissions. An
error is returned if you attempt to replace a procedure that is already in use.
• RESULT – declares the column names and their data types for the result set of the external
UDF. The data types of the columns must be a valid SQL data type (e.g., a column in the
result set cannot have TABLE as data type). The set of datums in the result implies the
TABLE. External UDFs can only have one result set of type TABLE.
Note: TABLE is not an output value. A table UDF cannot have LONG VARBINARY or
LONG VARCHAR data types in its result set, but a table parameterized function (TPF) can
have large object (LOB) data in its result set.
A TPF cannot produce LOB data, but can have columns in the result set as LOB data types.
However, the only way to get LOB data in the output is to pass a column from an input table
to the output table. The describe attribute
EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT allows this, as
illustrated in the sample file tpf_blob.cxx.
• SQL SECURITY – defines whether the procedure is executed as the INVOKER (the user
who is calling the UDF), or as the DEFINER (the user who owns the UDF). The default is
DEFINER.
When SQL SECURITY INVOKER is specified, more memory is used because annotation
must be done for each user that calls the procedure. Also, when SQL SECURITY
INVOKER is specified, name resolution is done as the invoker as well. Therefore, care
should be taken to qualify all object names (tables, procedures, and so on) with their
appropriate owner. For example, suppose user1 creates this procedure:
If user2 attempts to run this procedure and a table user2.table1 does not exist, a table
lookup error results. Additionally, if a user2.table1 does exist, that table is used instead of
the intended user1.table1. To prevent this situation, qualify the table reference in the
statement (user1.table1, instead of just table1).
• EXTERNAL NAME – An external UDF must have EXTERNAL NAME clause which
defines an interface to a function written in a programming language such as C. The
function is loaded by the database server into its address space.
The library name can include the file extension, which is typically .dll on Windows and .so
on UNIX. In the absence of the extension, the software appends the platform-specific
default file extension for libraries. This is a formal example.
CREATE PROCEDURE mystring( IN instr CHAR(255),
IN input_table TABLE(A INT) )
RESULT (CHAR(255))
EXTERNAL NAME
'mystring@mylib.dll;Unix:mystring@mylib.so'
A simpler way to write the preceding EXTERNAL NAME clause, using platform-specific
defaults, is as follows:
CREATE PROCEDURE mystring( IN instr CHAR(255),
IN input_table TABLE(A INT) )
RESULT (CHAR(255))
EXTERNAL NAME ‘mystring@mylib’
Usage
(back to top) on page 169
You define table UDFs using the a_v4_extfn API. CREATE PROCEDURE statement
reference information for external procedures that do not use the a_v3_extfn or
a_v4_extfn APIs is located in a separate topic. CREATE PROCEDURE statement reference
information for Java UDFs is located in a separate topic.
The CREATE PROCEDURE statement creates a procedure in the database. To create a
procedure for themselves, a user must have the CREATE PROCEDURE system privilege. To
create a procedure for others, a user must specify the owner of the procedure and must have
either the CREATE ANY PROCEDURE or CREATE ANY OBJECT system privilege. If the
procedure contains an external reference, the user must have the CREATE EXTERNAL
REFERENCE system privilege in addition to previously mentioned system privileges,
regardless of who owns the procedure.
If a stored procedure returns a result set, it cannot also set output parameters or return a return
value.
When referencing a temporary table from multiple procedures, a potential issue can arise if the
temporary table definitions are inconsistent and statements referencing the table are cached.
Use caution when referencing temporary tables within procedures.
You can use the CREATE PROCEDURE statement to create external table UDFs implemented
in a different programming language than SQL. However, be aware of the table UDF
restrictions before creating external UDFs.
The data type for a scalar parameter, a result column, and a column of a TABLE parameter
must be a valid SQL data type.
Parameter names must conform to the rules for other database identifiers such as column
names. They must be a valid SQL data type.
TPFs support a mix scalar parameters and single TABLE parameter. A TABLE parameter
must define a schema for an input set of rows to be processed by the UDF. The definition of a
TABLE parameter includes column names and column data types.
TABLE(c1 INT, c2 CHAR(20))
The above example defines a schema with the two columns c1 and c2 of types INT and
CHAR(20). Each row processed by the UDF must be a tuple with two (2) values. TABLE
parameters, unlike scalar parameters cannot be assigned a default value.
Standards
(back to top) on page 169
• SQL—ISO/ANSI SQL compliant.
• SAP Sybase Database product—The Transact-SQL CREATE PROCEDURE statement is
different.
• SQLJ—The syntax extensions for Java result sets are as specified in the proposed SQLJ1
standard.
Permissions
(back to top) on page 169
Unless creating a temporary procedure, a user must have the CREATE PROCEDURE system
privilege to create a UDF for themselves. To create a UDF for others, they must specify the
owner of the procedure and must have either the CREATE ANY PROCEDURE or CREATE
ANY OBJECT system privilege. If the procedure contains an external reference, a user must
also have the CREATE EXTERNAL REFERENCE system privilege, in addition to the
previously mentioned system privileges.
See also
• Sample Files on page 99
Syntax
Syntax 1
CREATE [ OR REPLACE ] [ TEMPORARY ] FUNCTION [ owner.]function-name
( [ parameter, … ] )
[ SQL SECURITY { INVOKER | DEFINER } ]
RETURNS data-type ON EXCEPTION RESUME
| [ NOT ] DETERMINISTIC
{ compound-statement | AS tsql-compound-statement
| EXTERNAL NAME library-call
| EXTERNAL NAME java-call LANGUAGE JAVA }
Syntax 2
CREATE FUNCTION [ owner.]function-name ( [ parameter, … ] )
RETURNS data-type
URL url-string
[ HEADER header-string ]
[ SOAPHEADER soap-header-string ]
[ TYPE { 'HTTP[:{ GET | POST } ] ' | 'SOAP[:{ RPC | DOC } ]' } ]
[ NAMESPACE namespace-string ]
[ CERTIFICATE certificate-string ]
[ CLIENTPORT clientport-string ]
[ PROXY proxy-string ]
Parameters
(back to top) on page 173
• CREATE [ OR REPLACE ] – parameter names must conform to the rules for database
identifiers. They must have a valid SQL data type and be prefixed by the keyword IN,
signifying that the argument is an expression that provides a value to the function.
The CREATE clause creates a new function, while the OR REPLACE clause replaces an
existing function with the same name. When a function is replaced, the definition of the
function is changed but the existing permissions are preserved. You cannot use the OR
REPLACE clause with temporary functions.
• TEMPORARY – the function is visible only by the connection that created it, and that it is
automatically dropped when the connection is dropped. Temporary functions can also be
explicitly dropped. You cannot perform ALTER, GRANT, or REVOKE operations on them,
and unlike other functions, temporary functions are not recorded in the catalog or
transaction log.
Temporary functions execute with the permissions of their creator (current user), and can
only be owned by their creator. Therefore, do not specify owner when creating a temporary
function. They can be created and dropped when connected to a read-only database.
• SQL SECURITY – defines whether the function is executed as the INVOKER, the user
who is calling the function, or as the DEFINER, the user who owns the function. The
default is DEFINER.
When INVOKER is specified, more memory is used because annotation must be done for
each user that calls the procedure. Also, name resolution is done as the invoker as well.
Therefore, take care to qualify all object names (tables, procedures, and so on) with their
appropriate owner.
• data-type – LONG BINARY and LONG VARCHAR are not permitted as return-value
data types.
Functions may be declared as DETERMINISTIC if they always return the same value for
given input parameters. All user-defined functions are treated as deterministic unless they
are declared NOT DETERMINISTIC. Deterministic functions return a consistent result
for the same parameters and are free of side effects. That is, the database server assumes
that two successive calls to the same function with the same parameters will return the
same result without unwanted side-effects on the semantics of the query.
• URL – for use only when defining an HTTP or SOAP web services client function.
Specifies the URL of the web service. The optional user name and password parameters
provide a means of supplying the credentials needed for HTTP basic authentication. HTTP
basic authentication base-64 encodes the user and password information and passes it in
the “Authentication” header of the HTTP request.
For web service client functions, the return type of SOAP and HTTP functions must one of
the character data types, such as VARCHAR. The value returned is the body of the HTTP
response. No HTTP header information is included. If more information is required, such
as status information, use a procedure instead of a function.
Parameter values are passed as part of the request. The syntax used depends on the type of
request. For HTTP:GET, the parameters are passed as part of the URL; for HTTP:POST
requests, the values are placed in the body of the request. Parameters to SOAP requests are
always bundled in the request body.
• HEADER – when creating HTTP web service client functions, use this clause to add or
modify HTTP request header entries. Only printable ASCII characters can be specified for
HTTP headers, and they are case-insensitive. For more information about how to use this
clause, see the HEADER clause of the CREATE PROCEDURE Statement.
• SOAPHEADER – when declaring a SOAP Web service as a function, use this clause to
specify one or more SOAP request header entries. A SOAP header can be declared as a
static constant, or can be dynamically set using the parameter substitution mechanism
(declaring IN, OUT, or INOUT parameters for hd1, hd2, and so on). A web service
function can define one or more IN mode substitution parameters, but cannot define an
INOUT or OUT substitution parameter.
• TYPE – specifies the format used when making the web service request. If SOAP is
specified or no type clause is included, the default type SOAP:RPC is used. HTTP implies
HTTP:POST. Since SOAP requests are always sent as XML documents, HTTP:POST is
always used to send SOAP requests.
• NAMESPACE – applies to SOAP client functions only and identifies the method
namespace usually required for both SOAP:RPC and SOAP:DOC requests. The SOAP
server handling the request uses this namespace to interpret the names of the entities in the
SOAP request message body. The namespace can be obtained from the WSDL description
of the SOAP service available from the web service server. The default value is the
procedure's URL, up to but not including the optional path component.
• CERTIFICATE – to make a secure (HTTPS) request, a client must have access to the
certificate used by the HTTPS server. The necessary information is specified in a string of
semicolon-separated key/value pairs. The certificate can be placed in a file and the name of
the file provided using the file key, or the whole certificate can be placed in a string, but not
both. These keys are available:
Certificates are required only for requests that are either directed to an HTTPS server or
can be redirected from an insecure to a secure server.
• CLIENTPORT – identifies the port number on which the HTTP client procedure
communicates using TCP/IP. It is provided for and recommended only for connections
across firewalls, as firewalls filter according to the TCP/UDP port. You can specify a single
port number, ranges of port numbers, or a combination of both; for example,
CLIENTPORT '85,90-97'.
• PROXY – specifies the URI of a proxy server. For use when the client must access the
network through a proxy. Indicates that the procedure is to connect to the proxy server and
send the request to the web service through it.
Examples
(back to top) on page 173
• Example 1 – concatenates a firstname string and a lastname string:
CREATE FUNCTION fullname (
firstname CHAR(30),
lastname CHAR(30) )
RETURNS CHAR(61)
BEGIN
DECLARE name CHAR(61);
SET name = firstname || ' ' || lastname;
RETURN (name);
END
fullname('joe', 'smith')
joe smith
Usage
(back to top) on page 173
To modify a user-defined function, or to hide the contents of a function by scrambling its
definition, use the ALTER FUNCTION statement.
When functions are executed, not all parameters need to be specified. If a default value is
provided in the CREATE FUNCTION statement, missing parameters are assigned the default
values. If an argument is not provided by the caller and no default is set, an error is given.
Side Effects
• Automatic commit
Standards
(back to top) on page 173
• SQL—ISO/ANSI SQL compliant.
• SAP Sybase Database product—Not supported by Adaptive Server.
Permissions
(back to top) on page 173
For function to be owned by self – Requires the CREATE PROCEDURE system privilege.
For function to be owned by any user – Requires one of:
• CREATE ANY PROCEDURE system privilege.
• CREATE ANY OBJECT system privilege.
To create a function containing an external reference, regardless of whether or not they are the
owner of the function, also requires the CREATE EXTERNAL REFERENCE system
privilege.
DEFAULT_TABLE_UDF_ROW_COUNT Option
Enables you to override the default estimate of the number of rows to return from a table UDF
(either a C, C++, or Java table UDF).
Allowed Values
0 to 4294967295
Default
200000
Scope
Option can be set at the database (PUBLIC) or user level. When set at the database level, the
value becomes the default for any new user, but has no impact on existing users. When set at
the user level, overrides the PUBLIC value for that user only. No system privilege is required
to set option for self. System privilege is required to set at database level or at user level for any
user other than self.
Requires the SET ANY PUBLIC OPTION system privilege to set this option. Can be set
temporary for an individual connection or for the PUBLIC role. Takes effect immediately.
Remarks
A table UDF can use the DEFAULT_TABLE_UDF_ROW_COUNT option to give the query
processor an estimate for the number of rows that a table UDF will return. This is the only way
a Java table UDF can convey this information. However, for a C or C++ table UDF, the UDF
developer should consider publishing this information in the describe phase using the
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_ROWS describe parameter to publish the
number of rows it expects to return. The value of
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_ROWS always overrides the value of the
DEFAULT_PROXY_TABLE_UDF_ROW_COUNT option.
See also
• Query Processing States on page 121
TABLE_UDF_ROW_BLOCK_CHUNK_SIZE_KB Option
Controls the size, in kilobytes, for server-allocated row blocks. Row blocks are used by Table
UDFs and TPFs.
Allowed Values
0 to 4294967295
Default
128
Scope
Option can be set at the database (PUBLIC) or user level. When set at the database level, the
value becomes the default for any new user, but has no impact on existing users. When set at
the user level, overrides the PUBLIC value for that user only. No system privilege is required
to set option for self. System privilege is required to set at database level or at user level for any
user other than self.
Requires the SET ANY PUBLIC OPTION system privilege to set this option. Can be set
temporary for an individual connection or for the PUBLIC role. Takes effect immediately.
Description
Specifies the row block size, in kilobytes, to fetch from the server.
The server allocates row blocks when you use fetch_into to fetch rows from a table UDF,
and when you use fetch_block to fetch rows from a TPF input table.
The row block contains as many rows as will fit into the specified size. If you specify a row
block size smaller than the size required for a single row, the server allocates the size of one
row.
FROM Clause
Specifies the database tables or views involved in a SELECT statement.
Quick Links:
Go to Parameters on page 183
Go to Examples on page 186
Go to Usage on page 186
Go to Standards on page 187
Go to Permissions on page 188
Syntax
...FROM table-expression [,...]
Parameters
(back to top) on page 180
• table-name – a base table or temporary table. Tables owned by a different user can be
qualified by specifying the user ID. Tables owned by groups to which the current user
belongs are found by default without specifying the user ID.
• view-name – specifies a view to include in the query. As with tables, views owned by a
different user can be qualified by specifying the user ID. Views owned by groups to which
the current user belongs are found by default without specifying the user ID. Although the
syntax permits table hints on views, these hints have no effect.
• procedure-name – a stored procedure that returns a result set. This clause applies to the
FROM clause of SELECT statements only. The parentheses following the procedure name
are required even if the procedure does not take parameters. DEFAULT can be specified in
place of an optional parameter.
• parameter – specifies a scalar-parameter or table-parameter clause. A scalar-parameter
are any objects of a valid SQL datatype. A table-parameter can be specified using a table,
view or common table-expression name which are treated as new instance of this object if
the object is also used outside the table-parameter.
This query illustrates a valid FROM clause where the two references to the same table T are
treated as two different instances of the same table T.
SELECT * FROM T, my_proc(TABLE(SELECT T.Z, T.X FROM T)
OVER(PARTITION BY T.Z));
If a subquery is used to define the TABLE parameter, then the following restrictions must
hold:
• The table-parameter clause must be of type IN.
• PARTITION BY or ORDER BY clauses must refer to the columns of the derived table
and outer references. An expression in the expression-list can be an integer K which
refers to the Kth column of the TABLE input parameter.
Note: A Table UDF can only be referenced in a FROM clause of a SQL statement.
• PARTITION BY – logically specifies how the invocation of the function will be
performed by the execution engine. The execution engine must invoke the function for
each partition and the function must process a whole partition in each invocation.
PARTITION BY clause also specifies how the input data must be partitioned such that
each invocation of the function will process exactly one partition of data. The function
must be invoked the number of times equal to the number of partitions. For TPF, the
parallelism characteristics are established through dynamic negotiation between the
server and the UDF at the runtime. If the TPF can be executed in parallel, for N input
partitions, the function can be instantiated M times, with M <=N. Each instantiation of the
function can be invoked more than once, each invocation consuming exactly one partition.
You can specify only one TABLE input parameter for PARTITION BY expression-list or
PARTITION BY ANY clause. For all other TABLE input parameters you must specify,
explicit or implicit PARTITION BY NONE clause.
Note: The execution engine can invoke the function in any order of the partitions and the
function is assumed to return the same result sets regardless of the partitions order.
Partitions cannot be split among two invocations of the function.
• ORDER BY – specifies that the input data in each partition is expected to be sorted by
expression-list by the execution engine. The UDF expects each partition to have this
physical property. If only one partition exists, the whole input data is ordered based on the
ORDER BY specification. ORDER BY clause can be specified for any of the TABLE
input parameters with PARTITION BY NONE or without PARTITION BY clause.
• derived-table – you can supply a SELECT statement instead of table or view name in the
FROM clause. A SELECT statement used in this way is called a derived table, and it must
be given an alias. For example, the following statement contains a derived table,
MyDerivedTable, which ranks products in the Products table by UnitPrice.
SELECT TOP 3 *
FROM ( SELECT Description,
Quantity,
UnitPrice,
RANK() OVER ( ORDER BY UnitPrice ASC )
AS Rank
FROM Products ) AS MyDerivedTable
ORDER BY Rank;
Keyword Description
LEFT OUTER JOIN Preserves unmatched rows from the left table, but discards un-
matched rows from the right table
RIGHT OUTER JOIN Preserves unmatched rows from the right table, but discards
unmatched rows from the left table
FULL OUTER JOIN Retains unmatched rows from both the left and the right tables
Do not mix comma-style joins and keyword-style joins in the FROM clause. The same
query can be written two ways, each using one of the join styles. The ANSI syntax
keyword style join is preferable.
This query uses a comma-style join:
SELECT *
FROM Products pr, SalesOrders so, SalesOrderItems si
WHERE pr.ProductID = so.ProductID
AND pr.ProductID = si.ProductID;
The ON clause filters the data of inner, left, right, and full joins. Cross joins do not have an
ON clause. In an inner join, the ON clause is equivalent to a WHERE clause. In outer joins,
however, the ON and WHERE clauses are different. The ON clause in an outer join filters
the rows of a cross product and then includes in the result the unmatched rows extended
with nulls. The WHERE clause then eliminates rows from both the matched and
unmatched rows produced by the outer join. You must take care to ensure that unmatched
rows you want are not eliminated by the predicates in the WHERE clause.
You cannot use subqueries inside an outer join ON clause.
• openstring-expression – Specify an OPENSTRING clause to query within a file or a
BLOB, treating the content of these sources as a set of rows. When doing so, you also
specify information about the schema of the file or BLOB for the result set to be generated,
since you are not querying a defined structure such as a table or view. This clause applies to
the FROM clause of a SELECT statement. It is not supported for UPDATE or DELETE
statements.
• apply-expression – Use this clause to specify a join condition where the right table-
expression is evaluated for every row in the left table-expression. For example, you can use
an apply expression to evaluate a function, procedure, or derived table for each row in a
table expression.
• contains-expression – Use the CONTAINS clause after a table name to filter the table,
and return only those rows matching the full text query specified with contains-query.
Every matching row of the table is returned, along with a score column that can be referred
to using score-correlation-name, if it is specified. If score-correlation-name is not
specified, then the score column can be referred to by the default correlation name,
contains.
• dml-derived-table – Supports the use of a DML statement (INSERT, UPDATE, or
DELETE) as a table expression in a query's FROM clause.
Examples
(back to top) on page 180
• Example 1 – these are valid FROM clauses:
...
FROM Employees
...
...
FROM Employees NATURAL JOIN Departments
...
...
FROM Customers
KEY JOIN SalesOrders
KEY JOIN SalesOrderItems
KEY JOIN Products
...
• Example 2 – this query illustrates how to use derived tables in a query:
SELECT Surname, GivenName, number_of_orders
FROM Customers JOIN
( SELECT CustomerID, count(*)
FROM SalesOrders
GROUP BY CustomerID )
AS sales_order_counts ( CustomerID,
number_of_orders )
ON ( Customers.ID = sales_order_counts.cust_id )
WHERE number_of_orders > 3
Usage
(back to top) on page 180
The SELECT statement requires a table list to specify which tables are used by the statement.
Note: Although this description refers to tables, it also applies to views unless otherwise
noted.
The FROM table list creates a result set consisting of all the columns from all the tables
specified. Initially, all combinations of rows in the component tables are in the result set, and
the number of combinations is usually reduced by join conditions and/or WHERE conditions.
Tables owned by a different user can be qualified by specifying the userid. Tables owned by
roles to which the current user belongs are found by default without specifying the user ID.
The correlation name is used to give a temporary name to the table for this SQL statement only.
This is useful when referencing columns that must be qualified by a table name but the table
name is long and cumbersome to type. The correlation name is also necessary to distinguish
between table instances when referencing the same table more than once in the same query. If
no correlation name is specified, then the table name is used as the correlation name for the
current statement.
If the same correlation name is used twice for the same table in a table expression, that table is
treated as if it were only listed once. For example, in:
SELECT *
FROM SalesOrders
KEY JOIN SalesOrderItems,
SalesOrders
KEY JOIN Employees
The two instances of the SalesOrders table are treated as one instance that is equivalent
to:
SELECT *
FROM SalesOrderItems
KEY JOIN SalesOrders
KEY JOIN Employees
By contrast, the following is treated as two instances of the Person table, with different
correlation names HUSBAND and WIFE.
SELECT *
FROM Person HUSBAND, Person WIFE
Standards
(back to top) on page 180
Permissions
(back to top) on page 180
Must be connected to the database.
SELECT Statement
Retrieves information from the database.
Quick Links:
Go to Parameters on page 189
Go to Examples on page 195
Go to Usage on page 196
Go to Standards on page 197
Go to Permissions on page 197
Syntax
SELECT [ ALL | DISTINCT ] [ row-limitation-option1 ] select-list
… [ INTO { host-variable-list | variable-list | table-name } ]
… [ INTO LOCAL TEMPORARY TABLE { table-name } ]
… [ FROM table-list ]
… [ WHERE search-condition ]
… [ GROUP BY [ expression [, ...]
| ROLLUP ( expression [, ...] )
| CUBE ( expression [, ...] ) ] ]
… [ HAVING search-condition ]
… [ ORDER BY { expression | integer } [ ASC | DESC ] [, ...] ]
| [ FOR JSON json-mode ]
… [ row-limitation-option ]
simple-expression
Parameters
(back to top) on page 188
• ALL or DISTINCT – filters query results. If neither is specified, all rows that satisfy the
clauses of the SELECT statement are retrieved. If DISTINCT is specified, duplicate output
rows are eliminated. This is called the projection of the result of the statement. In many
cases, statements take significantly longer to execute when DISTINCT is specified, so
reserve the use of DISTINCT for cases where it is necessary.
If DISTINCT is used, the statement cannot contain an aggregate function with a
DISTINCT parameter.
• row-limitation-option1 – specifies the number of rows returned from a query. FIRST
returns the first row selected from the query. TOP returns the specified number of rows
from the query where number-of-rows is in the range 1 – 2147483647 and can be an integer
constant or integer variable.
Note: You cannot use TOP and LIMIT in the same query.
FIRST and TOP are used primarily with the ORDER BY clause. If you use these keywords
without an ORDER BY clause, the result might vary from run to run of the same query, as
the optimizer might choose a different query plan.
FIRST and TOP are permitted only in the top-level SELECT of a query, so they cannot be
used in derived tables or view definitions. Using FIRST or TOP in a view definition might
result in the keyword being ignored when a query is run on the view.
Using FIRST is the same as setting the ROW_COUNT database option to 1. Using TOP is
the same as setting the ROW_COUNT option to the same number of rows. If both TOP and
ROW_COUNT are set, then the value of TOP takes precedence.
The ROW_COUNT option could produce inconsistent results when used in a query
involving global variables, system functions or proxy tables. See ROW_COUNT Option
for details.
• select-list – is a comma delimited list of expressions that specify what is retrieved from the
database. If an asterisk (*) is specified, all columns of all tables in the FROM clause
(table-name all columns of the named table) are selected. Aggregate functions and
analytical functions are allowed in the select-list.
Note: In SAP Sybase IQ, scalar subqueries (nested selects) are allowed in the select list of
the top level SELECT, as in SQL Anywhere and Adaptive Server. Subqueries cannot be
used inside a conditional value expression (for example, in a CASE statement).
Subqueries can also be used in a WHERE or HAVING clause predicate (one of the
supported predicate types). However, inside the WHERE or HAVING clause, subqueries
cannot be used inside a value expression or inside a CONTAINS or LIKE predicate.
Subqueries are not allowed in the ON clause of outer joins or in the GROUP BY clause.
• alias-names – can be used throughout the query to represent the aliased expression. Alias
names are also displayed by Interactive SQL at the top of each column of output from the
SELECT statement. If the optional alias-name is not specified after an expression,
Interactive SQL displays the expression. If you use the same name or expression for a
column alias as the column name, the name is processed as an aliased column, not a table
column name.
• INTO host-variable-list – specifies where the results of the SELECT statement goes.
There must be one host-variable item for each item in the select-list. Select list items are
put into the host variables in order. An indicator host variable is also allowed with each
host-variable so the program can tell if the select list item was NULL. Used in Embedded
SQL only.
• INTO variable-list – specifies where the results of the SELECT statement go. There must
be one variable for each item in the select list. Select list items are put into the variables in
order. Used in procedures only
• INTO table-name – creates a table and fills the table with data.
If the table name starts with #, the table is created as a temporary table. Otherwise, the table
is created as a permanent base table. For permanent tables to be created, the query must
satisfy these conditions:
• The select-list contains more than one item, and the INTO target is a single table-name
identifier, or
• The select-list contains a * and the INTO target is specified as owner.table.
To create a permanent table with one column, the table name must be specified as
owner.table. Omit the owner specification for a temporary table.
This statement causes a COMMIT before execution as a side effect of creating the table.
Requires the CREATE TABLE system privilege to execute this statement. No permissions
are granted on the new table: the statement is a short form for CREATE TABLE followed by
INSERT... SELECT.
A SELECT INTO from a stored procedure or function is not permitted, as SELECT INTO is
an atomic statement and you cannot do COMMIT, ROLLBACK, or some ROLLBACK TO
SAVEPOINT statements in an atomic statement.
Tables created using this statement do not have a primary key defined. You can add a
primary key using ALTER TABLE. A primary key should be added before applying any
updates or deletes to the table; otherwise, these operations result in all column values being
logged in the transaction log for the affected rows.
Use of this clause is restricted to valid SQL Anywhere queries. SAP Sybase IQ extensions
are not supported.
• INTO LOCAL TEMPORARY TABLE – creates a local, temporary table and populates
it with the results of the query. When you use this clause, you do not need to start the
temporary table name with #.
• FROM table-list – retrieves rows and views specified in the table-list. Joins can be
specified using join operators. For more information, see FROM Clause. A SELECT
statement with no FROM clause can be used to display the values of expressions not
derived from tables. For example:
SELECT @@version
displays the value of the global variable @@version. This is equivalent to:
SELECT @@version
FROM DUMMY
Note: If you omit the FROM clause, or if all tables in the query are in the SYSTEM dbspace,
the query is processed by SQL Anywhere instead of SAP Sybase IQ and might behave
differently, especially with respect to syntactic and semantic restrictions and the effects of
option settings.
If you have a query that does not require a FROM clause, you can force the query to be
processed by SAP Sybase IQ by adding the clause “FROM iq_dummy,” where
iq_dummy is a one-row, one-column table that you create in your database.
• WHERE search-condition – specifies which rows are selected from the tables named in
the FROM clause. It is also used to do joins between multiple tables. This is accomplished
by putting a condition in the WHERE clause that relates a column or group of columns
from one table with a column or group of columns from another table. Both tables must be
listed in the FROM clause.
The use of the same CASE statement is not allowed in both the SELECT and the WHERE
clause of a grouped query.
SAP Sybase IQ also supports the disjunction of subquery predicates. Each subquery can
appear within the WHERE or HAVING clause with other predicates and can be combined
using the AND or OR operators.
• GROUP BY – groups columns, alias names, or functions. GROUP BY expressions must
also appear in the select list. The result of the query contains one row for each distinct set of
values in the named columns, aliases, or functions. The resulting rows are often referred to
as groups since there is one row in the result for each group of rows from the table list. In
the case of GROUP BY, all NULL values are treated as identical. Aggregate functions can
then be applied to these groups to get meaningful results.
GROUP BY must contain more than a single constant. You do not need to add constants to
the GROUP BY clause to select the constants in grouped queries. If the GROUP BY
expression contains only a single constant, an error is returned and the query is rejected.
When GROUP BY is used, the select list, HAVING clause, and ORDER BY clause cannot
reference any identifiers except those named in the GROUP BY clause. This exception
applies: The select-list and HAVING clause may contain aggregate functions.
• ROLLUP operator – subtotals GROUP BY expressions that roll up from a detailed level
to a grand total.
The ROLLUP operator requires an ordered list of grouping expressions to be supplied as
arguments. ROLLUP first calculates the standard aggregate values specified in the
GROUP BY. Then ROLLUP moves from right to left through the list of grouping columns
and creates progressively higher-level subtotals. A grand total is created at the end. If n is
the number of grouping columns, ROLLUP creates n+1 levels of subtotals.
Restrictions on the ROLLUP operator:
• ROLLUP supports all of the aggregate functions available to the GROUP BY clause,
but ROLLUP does not currently support COUNT DISTINCT and SUM DISTINCT.
• ROLLUP can be used only in the SELECT statement; you cannot use ROLLUP in a
SELECT subquery.
• A multiple grouping specification that combines ROLLUP, CUBE, and GROUP BY
columns in the same GROUP BY clause is not currently supported.
• Constant expressions as GROUP BY keys are not supported.
GROUPING is used with the ROLLUP operator to distinguish between stored NULL
values and NULL values in query results created by ROLLUP.
ROLLUP syntax:
SELECT … [ GROUPING ( column-name ) …] …
GROUP BY [ expression [, …]
| ROLLUP ( expression [, …] ) ]
When generating a query plan, the SAP Sybase IQ optimizer estimates the total number of
groups generated by the GROUP BY CUBE hash operation. The MAX_CUBE_RESULTS
database option sets an upper boundary for the number of estimated rows the optimizer
considers for a hash algorithm that can be run. If the actual number of rows exceeds the
MAX_CUBE_RESULT option value, the optimizer stops processing the query and returns
Note: You cannot specify TOP and LIMIT in the same query.
Examples
(back to top) on page 188
• Example 1 – list all tables and views in the system catalog:
SELECT tname
FROM SYS.SYSCATALOG
WHERE tname LIKE 'SYS%' ;
• Example 2 – list all customers and the total value of their orders:
SELECT CompanyName,
CAST( sum(SalesOrderItems.Quantity *
Products.UnitPrice) AS INTEGER) VALUE
FROM Customers
LEFT OUTER JOIN SalesOrders
LEFT OUTER JOIN SalesOrderItems
LEFT OUTER JOIN Products
GROUP BY CompanyName
ORDER BY VALUE DESC
• Example 3 – list the number of employees:
SELECT count(*)
FROM Employees;
• Example 4 – an Embedded SQL SELECT statement:
SELECT count(*) INTO :size FROM Employees;
• Example 5 – list the total sales by year, model, and color:
SELECT year, model, color, sum(sales)
FROM sales_tab
GROUP BY ROLLUP (year, model, color);
• Example 6 – select all items with a certain discount into a temporary table:
SELECT * INTO #TableTemp FROM lineitem
WHERE l_discount < 0.5
• Example 7 – return information about the employee that appears first when employees are
sorted by last name:
SELECT FIRST *
FROM Employees
ORDER BY Surname;
• Example 8 – return the first five employees when their names are sorted by last name:
SELECT TOP 5 *
FROM Employees
ORDER BY Surname;
SELECT *
FROM Employees
ORDER BY Surname
LIMIT 5;
• Example 9 – list the fifth and sixth employees sorted in descending order by last name:
SELECT *
FROM Employees
ORDER BY Surname DESC
LIMIT 4,2;
Usage
(back to top) on page 188
You can use a SELECT statement in Interactive SQL to browse data in the database or to export
data from the database to an external file.
You can also use a SELECT statement in procedures or in Embedded SQL. The SELECT
statement with an INTO clause is used for retrieving results from the database when the
SELECT statement returns only one row. (Tables created with SELECT INTO do not inherit
IDENTITY/AUTOINCREMENT tables.) For multiple-row queries, you must use cursors.
When you select more than one column and do not use #table, SELECT INTO creates a
permanent base table. SELECT INTO #table always creates a temporary table regardless of
the number of columns. SELECT INTO table with a single column selects into a host variable.
Note: When writing scripts and stored procedures that SELECT INTO a temporary table,
wrap any select list item that is not a base column in a CAST expression. This guarantees that
the column data type of the temporary table is the required data type.
Tables with the same name but different owners require aliases. A query without aliases
returns incorrect results:
SELECT * FROM user1.t1
WHERE NOT EXISTS
(SELECT *
FROM user2.t1
WHERE user2.t1.col1 = user1.t.col1);
Standards
(back to top) on page 188
• SQL—ISO/ANSI SQL compliant.
• SAP Sybase Database product—Supported by SAP Sybase IQ, with some differences in
syntax.
Permissions
(back to top) on page 188
Requires SELECT privilege on the named tables and views.
Blob (a_v4_extfn_blob)
Use the a_v4_extfn_blob structure to represent a free-standing blob object.
Implementation
typedef struct a_v4_extfn_blob {
a_sql_uint64 (SQL_CALLBACK *blob_length)(a_v4_extfn_blob *blob);
void (SQL_CALLBACK *open_istream)(a_v4_extfn_blob *blob,
a_v4_extfn_blob_istream **is);
void (SQL_CALLBACK *close_istream)(a_v4_extfn_blob *blob,
a_v4_extfn_blob_istream *is);
void (SQL_CALLBACK *release)(a_v4_extfn_blob *blob);
} a_v4_extfn_blob;
Method Summary
Method Name Data Type Description
blob_length a_sql_uint64 Returns the length, in
bytes, of the specified
blob.
Description
The object a_v4_extfn_blob is used when:
• a table UDF needs to read LOB or CLOB data from a scalar input value
• a TPF needs to read LOB or CLOB data from a column in an input table
blob_length
Use the blob_length v4 API method to return the length, in bytes, of the specified blob.
Declaration
a_sql_uint64 blob_length(
a_v4_extfn_blob *
)
Usage
Returns the length, in bytes, of the specified blob.
Parameters
Parameter Description
blob The blob to return the length of.
Returns
The length of the specified blob.
See also
• open_istream on page 201
• close_istream on page 201
open_istream
Use the open_istream v4 API method to open an input stream to read from a blob.
Declaration
void open_istream(
a_v4_extfn_blob *blob,
a_v4_extfn_blob_istream **is
)
Usage
Opens an input stream that can be used to begin reading from the specified blob.
Parameters
Parameter Description
blob The blob to open the input stream on.
Returns
Nothing.
See also
• blob_length on page 200
• close_istream on page 201
• release on page 202
close_istream
Use the close_istream v4 API method to close the input stream for the specified blob.
Declaration
void close_istream(
a_v4_extfn_blob *blob,
a_v4_extfn_blob_istream *is
)
Usage
Closes the input stream previously opened with the open_istream API.
Parameters
Parameter Description
Returns
Nothing.
See also
• blob_length on page 200
• open_istream on page 201
• release on page 202
release
Use the release v4 API method to indicate that the caller is done with the currently selected
blob. Releasing enables the owner to free memory.
Declaration
void release(
a_v4_extfn_blob *blob
)
Usage
Indicates that the caller is done with this blob and that the blob owner is free to release
resources. After release(), referencing the blob results in an error. The owner usually deletes
the memory when release() is called.
Parameters
Parameter Description
blob The blob to release.
Returns
Nothing.
See also
• blob_length on page 200
• open_istream on page 201
• close_istream on page 201
Implementation
typedef struct a_v4_extfn_blob_istream {
size_t (SQL_CALLBACK *get)( a_v4_extfn_blob_istream *is, void
*buf, size_t len );
a_v4_extfn_blob *blob;
a_sql_byte *beg;
a_sql_byte *ptr;
a_sql_byte *lim;
} a_v4_extfn_blob_istream;
Method Summary
Method Name Data Type Description
get size_t Gets a specified
amount of data from a
blob input stream.
get
Use the get v4 API method to get a specified amount of data from a blob input stream.
Declaration
size_t get(
a_v4_extfn_blob_istream *is,
void *buf,
size_t len
)
Usage
Gets a specified amount of data from a blob input stream.
Parameters
Parameter Description
is The input stream to retrieve data from.
Returns
The amount of data received.
Implementation
typedef struct a_v4_extfn_column_data {
a_sql_byte *is_null;
a_sql_byte null_mask;
a_sql_byte null_value;
void *data;
a_sql_uint32 *piece_len;
size_t max_piece_len;
void *blob_handle;
} a_v4_extfn_column_data;
is_null a_sql_byte * Points to a byte where the NULL information for the value is
stored.
null_mask a_sql_byte One or more bits used to represent the NULL value
data void * Pointer to the data for the column. Depending on the type of fetch
mechanism, either points to an address in the consumer, or an
address where the data is stored in the UDF.
piece_len a_sql_uint32 * The actual length of data for variable-length data types
max_piece_len size_t The maximum data length allowed for this column.
blob_handle void * A non-NULL value means that the data for this column must be
read using the blob API
Description
The a_v4_extfn_column_data structure represents the data values and related
attributes for a specific data column. This structure is used by the producer when generating
result set data. Data producers are also expected to create storage for data, piece_len, and the
is_null flag.
The is_null, null_mask, and null_value data members indicate null in a column, and handle
situations in which the null-bits are encoded into one byte for eight columns, or other cases in
which a full byte is used for each column.
This example shows how to interpret the three fields used to represent NULL: is_null,
null_mask, and null_value.
is_value_null()
return( (*is_null & null_mask) == null_value )
set_value_null()
*is_null = ( *is_null & ~null_mask) | null_value
set_value_not_null()
*is_null = *is_null & ~null_mask | (~null_value & null_mask)
See also
• get_blob on page 318
Implementation
typedef struct a_v4_extfn_column_list {
a_sql_int32 number_of_columns;
a_sql_uint32 column_indexes[1]; // there are
number_of_columns entries
} a_v4_extfn_column_list;
Description
The meaning of the contents of the column list changes, depending on whether the list is used
with TABLE_PARTITIONBY or TABLE_UNUSED_COLUMNS.
See also
• V4 API describe_parameter and
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY on page 141
• Parallel TPF PARTITION BY Examples Using
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY on page 143
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS Attribute (Get)
on page 260
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS Attribute (Set) on
page 276
Implementation
typedef struct a_v4_extfn_order_el {
a_sql_uint32 column_index; // Index of the column in the
table (1-based)
a_sql_byte ascending; // Nonzero if the column
is ordered "ascending".
} a_v4_extfn_order_el;
Description
The a_v4_extfn_order_el structure describes a column and tells whether it should be
in ascending or descending order. The a_v4_extfn_orderby_list structure holds an
array of these structures. There is one a_v4_extfn_order_el structure for each column
in the ORDERBY clause.
See also
• Order By List (a_v4_extfn_orderby_list) on page 307
Implementation
typedef struct a_v4_extfn_col_subset_of_input {
a_sql_uint32 source_table_parameter_arg_num; // arg_num of
the source table parameter
a_sql_uint32 source_column_number; // source column of
the source table
} a_v4_extfn_col_subset_of_input;
Description
The query optimizer uses the subset of input to infer logical properties of the values in the
output column. For example, the number of distinct values in the input column is an upper
bound on the distinct values in the output column, and any local predicates on the input column
also hold on the output column.
See also
• Describe Column Type (a_v4_extfn_describe_col_type) on page 281
Describe API
The _describe_extfn function is a member of a_v4_extfn_proc. A UDF gets and sets
logical properties using the describe_column, describe_parameter, and
describe_udf properties in the a_v4_extfn_proc_context object.
_describe_extfn Declaration
void (UDF_CALLBACK *_describe_extfn)(a_v4_extfn_proc_context
*cntxt );
)
Usage
The _describe_extfn function describes the procedure evaluation to the server.
Each of the describe_column, describe_parameter, and describe_udf
properties has an associated get and set method, a set of attribute types, and an associated data
type for each attribute. The get methods retrieve information from the server; the set methods
describe the logical properties of the UDF (such as the number of output columns or the
number of distinct values for a output column) to the server.
See also
• *describe_column_get on page 209
• *describe_column_set on page 225
• *describe_parameter_get on page 242
• *describe_parameter_set on page 261
• *describe_udf_get on page 277
• *describe_udf_set on page 279
• External Function (a_v4_extfn_proc) on page 288
*describe_column_get
The describe_column_get v4 API method is used by the table UDF to retrieve
properties about an individual column of a TABLE parameter.
Declaration
a_sql_int32 (SQL_CALLBACK *describe_column_get)(
a_v4_extfn_proc_context *cntxt,
a_sql_uint32 arg_num,
a_sql_uint32 column_num,
a_v4_extfn_describe_parm_type describe_type,
void *describe_buffer,
size_t describe_buffer_len );
Parameters
Parameter Description
cntxt The procedure context object for this UDF.
Returns
On success, returns the number of bytes written to the describe_buffer. If an error occurs, or
no property is retrieved, this function returns one of the generic describe_column errors.
See also
• *describe_column_set on page 225
EXTFNAPIV4_DESCRIBE_COL_CAN_BE_NULL,
EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES,
EXTFNAPIV4_DESCRIBE_COL_IS_UNIQUE,
EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT,
EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE,
EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER,
EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE,
EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE,
EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT,
} a_v4_extfn_describe_col_type;
EXTFNAPIV4_DESCRIBE_COL_NAME (Get)
The EXTFNAPIV4_DESCRIBE_COL_NAME attribute indicates the column name. Used in a
describe_column_get scenario.
Data Type
char[]
Description
The column name. This property is valid only for table arguments.
Usage
If a UDF gets this property, then the name of the specified column is returned.
Returns
On success, returns the length of the column name.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
buffer length has insufficient characters or is 0 length.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – get error returned if the
parameter is not a TABLE parameter.
See also
• EXTFNAPIV4_DESCRIBE_COL_NAME (Set) on page 227
EXTFNAPIV4_DESCRIBE_COL_TYPE (Get)
The EXTFNAPIV4_DESCRIBE_COL_TYPE attribute indicates the data type of the column.
Used in a describe_column_get scenario.
Data Type
a_sql_data_type
Description
The data type of the column. This property is valid only for table arguments.
Usage
If a UDF gets this property, then returns the data type of the specified column.
Returns
On success, the sizeof(a_sql_data_type) is returned.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe buffer is not the size of a_sql_data_type.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
See also
• Generic describe_column Errors on page 325
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Set) on page 228
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_WIDTH (Get)
The EXTFNAPIV4_DESCRIBE_COL_WIDTH attribute indicates the width of the column.
Used in a describe_column_get scenario.
Data Type
a_sql_uint32
Description
The width of a column. Column width is the amount of storage, in bytes, required to store a
value of the associated data type. This property is valid only for table arguments.
Usage
If a UDF gets this property, then returns the width of the column as defined in the CREATE
PROCEDURE statement.
Returns
On success, returns the sizeof(a_sql_uint32).
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
See also
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Set) on page 229
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_SCALE (Get)
The EXTFNAPIV4_DESCRIBE_COL_SCALE attribute indicates the scale of the column. Used
in a describe_column_get scenario.
Data Type
a_sql_uint32
Description
The scale of a column. For arithmetic data types, parameter scale is the number of digits to the
right of the decimal point in a number. This property is valid only for table arguments.
Usage
If the UDF gets this property, returns the scale of the column as defined in the CREATE
PROCEDURE statement. This property is valid only for arithmetic data types.
Returns
On success, returns the sizeof(a_sql_uint32) if the value was returned, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – get error returned if the scale is
unavailable for the data type of the specified column.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
See also
• EXTFNAPIV4_DESCRIBE_COL_SCALE (Set) on page 230
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_CAN_BE_NULL (Get)
The EXTFNAPIV4_DESCRIBE_COL_CAN_BE_NULL attribute indicates if the column can be
NULL. Used in a describe_column_get scenario.
Data Type
a_sql_byte
Description
True, if the column can be NULL. This property is valid only for table arguments. This
property is valid only for argument 0.
Usage
If a UDF gets this property, returns 1 if the column can be NULL, and returns 0 if otherwise.
Returns
On success, returns the sizeof(a_sql_byte) if the attribute is available, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – returned if the attribute was not
available to get. This can happen if the column was not involved in the query.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the specified
argument is an input table and the query processing phase is not greater than Plan Building
phase.
See also
• EXTFNAPIV4_DESCRIBE_COL_CAN_BE_NULL (Set) on page 231
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES (Get)
The EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES attribute describes the distinct
values for a column. Used in a describe_column_get scenario.
Data Type
a_v4_extfn_estimate
Description
The estimated number of distinct values for a column. This property is valid only for table
arguments.
Usage
If a UDF gets this property, it returns the estimated number of distinct values for a column.
Returns
On success, returns the sizeof(a_v4_extfn_estimate), if it returns a value, or:
Example
Consider this procedure definition and code fragment in the _describe_extfn API
function:
CREATE PROCEDURE my_tpf( col_char char(10), col_table TABLE( c1 INT,
c2 INT ) )
RESULTS ( r1 INT, r2 INT, r3 INT )
EXTERNAL ‘my_tpf_proc@mylibrary’;
CREATE TABLE T( x INT, y INT, z INT );
select * from my_tpf( 'test', TABLE( select x,y from T ) )
This example shows how a TPF gets the number of distinct values for column one of the input
table. A TPF may want to get this value, if it is beneficial for choosing an appropriate
processing algorithm.
my_tpf_describe(a_v4_extfn_proc_context *cntxt)
{
if( cntxt->current_state == EXTFNAPIV4_STATE_PLAN_BUILDING ) {
a_v4_extfn_estimate num_distinct;
a_sql_int32 ret = 0;
// default algorithm is 1
_algorithm = 1;
See also
• EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES (Set) on page 232
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_IS_UNIQUE (Get)
The EXTFNAPIV4_DESCRIBE_COL_IS_UNIQUE attribute indicates if a column is unique in
the table. Used in a describe_column_get scenario.
Data Type
a_sql_byte
Description
True, if the column is unique within the table. This property is valid only for table arguments.
Usage
If the UDF gets this property, then returns 1 if the column is unique, and 0 otherwise.
Returns
On success, returns the sizeof(a_sql_byte) or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – if the attribute was unavailable to get.
This can happen if the column was not involved in the query.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe buffer is not the size of a_sql_byte.
See also
• Generic describe_column Errors on page 325
• EXTFNAPIV4_DESCRIBE_COL_IS_UNIQUE (Set) on page 233
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT (Get)
The EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT attribute indicates if a column is
constant. Used in a describe_column_get scenario.
Data Type
a_sql_byte
Description
True, if the column is constant for the lifetime of the statement. This property is valid only for
input table arguments.
Usage
If a UDF gets this property, the return value is 1 if the column is constant for the lifetime of the
statement and 0 otherwise. Input table columns are constant, if the column in the select list for
the input table is a constant expression or NULL.
Returns
On success, returns the sizeof(a_sql_byte), if the value was returned, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – the attribute is not available to get.
Returned, if the column is not involved in the query.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned, if the
describe buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned, if the query
processing phase is not greater than Initial.
See also
• EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT (Set) on page 234
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE (Get)
The EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE attribute indicates the constant
value of a column. Used in a describe_column_get scenario.
Data Type
an_extfn_value
Description
The value of the column, if it is constant for the statement lifetime. If
EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT for this column returns true, this value
is available. This property is valid only for table arguments.
Usage
For columns of input tables that have a constant value, the value is returned. If the value is
unavailable, then NULL is returned.
Returns
On success, returns the sizeof(a_sql_byte), if the value was returned, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – the attribute is not available to get.
Returned, if the column is not involved in the query, or if the value is not considered
constant.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned, if the
describe buffer is not the size of a_sql_byte.
See also
• Generic describe_column Errors on page 325
• EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE (Set) on page 234
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER (Get)
The EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER attribute indicates if a
column in the result table is used by the consumer. Used in a describe_column_get
scenario.
Data Type
a_sql_byte
Description
Used either to determine whether a column in the result table is used by the consumer, or to
indicate that a column in an input is not needed. Valid for table arguments. Allows the user to
set or retrieve information about a single column, whereas the similar attribute
EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS sets or retrieves
information about all columns in a single call.
Usage
The UDF queries this property to determine if a result table column is required by the
consumer. This can help the UDF avoid unnecessary work for unused columns.
Returns
On success, returns the sizeof(a_sql_byte) or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – if the attribute was unavailable to get.
This can happen if the column was not involved in the query.
On failure, returns one of the generic describe_column errors, or:
When this TPF runs, it is beneficial to know if the user has selected column r1 of the result set.
If the user does not need r1, calculations for r1 may be unnecessary and we do not need to
produce it for the server.
my_tpf_describe(a_v4_extfn_proc_context *cntxt)
{
if( cntxt->current_state > EXTFNAPIV4_STATE_INITIAL ) {
a_sql_byte col_is_used = 0;
a_sql_int32 ret = 0;
See also
• EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER (Set) on page 235
EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE (Get)
The EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE attribute indicates the minimum
value for a column. Used in a describe_column_get scenario.
Data Type
an_extfn_value
Description
The minimum value for a column, if available. Valid only for argument 0 and table arguments.
Usage
If a UDF gets the EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE property, the minimum
value of the column data is returned in the describe_buffer. If the input table is a base table, the
minimum value is based on all of the column data in the table and is accessible only if there is
an index on the table column. If the input table is the result of another UDF, the minimum value
is the EXTFNAPIV4_DESCRIBE_COL_TYPE set by that UDF.
The data type for this property is different for different columns. The UDF can use
EXTFNAPIV4_DESCRIBE_COL_TYPE to determine the data type of the column. The UDF
can also use EXTFNAPIV4_DESCRIBE_COL_WIDTH to determine the storage
requirements of the column,to provide an equivalently sized buffer to hold the value.
describe_buffer_length allows the server to determine if the buffer is valid.
Returns
On success, returns the describe_buffer_length, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – if the attribute was unavailable to get.
Returned if the column was not involved in the query or the minimum value was
unavailable for the requested column.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – Get error returned, if the
describe buffer is not large enough to hold the minimum value.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – Get error returned if the state is not
greater than Initial.
• Annotation state
• Query Optimization state
• Plan Building state
• Execution state
Example
The procedure definition and code fragment in the _describe_extfn API function:
CREATE PROCEDURE my_tpf( col_char char(10), col_table TABLE( c1 INT,
c2 INT ) )
RESULTS ( r1 INT, r2 INT, r3 INT )
EXTERNAL ‘my_tpf_proc@mylibrary’;
This example illustrates how a TPF would get the minimum value for column two of the input
table, for internal optimization purposes.
my_tpf_describe(a_v4_extfn_proc_context *cntxt)
{
if( cntxt->current_state > EXTFNAPIV4_STATE_INITIAL ) {
a_sql_int32 min_value = 0;
a_sql_int32 ret = 0;
}
}
See also
• Query Processing States on page 121
• EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE (Set) on page 237
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Get) on page 211
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Set) on page 228
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Get) on page 212
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Set) on page 229
• Generic describe_column Errors on page 325
EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE (Get)
The EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE attribute indicates the maximum
value for the column. Used in a describe_column_get scenario.
Data Type
an_extfn_value
Description
The maximum value for a column. This property is valid only for argument 0 and table
arguments.
Usage
If a UDF gets the EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE property, then the
maximum value of the column data is returned in the describe_buffer. If the input table is a
base table, the maximum value is based on all of the column data in the table and is accessible
only if there is an index on the table column. If the input table is the result of another UDF, the
maximum value is the COL_MAXIMUM_VALUE set by that UDF.
The data type for this property is different for different columns. The UDF can use
EXTFNAPIV4_DESCRIBE_COL_TYPE to determine the data type of the column. The UDF
can also use EXTFNAPIV4_DESCRIBE_COL_WIDTH to determine the storage
requirements of the column, to provide an equivalently sized buffer to hold the value.
describe_buffer_length allows the server to determine if the buffer is valid.
If EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE is unavailable,
describe_buffer is NULL.
Returns
On success, returns the describe_buffer_length or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – If the attribute was unavailable to get.
This can happen if the column was uninvolved in the query, or if the maximum value was
unavailable for the requested column.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – Get error returned if the
describe buffer is not large enough to hold the maximum value.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – Get error returned if the query
processing phase is not greater than Initial.
• Annotation phase
• Query Optimization phase
• Plan building phase
• Execution phase
Example
The PROCEDURE definition and code fragment in the _describe_extfn API function:
CREATE PROCEDURE my_tpf( col_char char(10), col_table TABLE( c1 INT,
c2 INT ) )
RESULTS ( r1 INT, r2 INT, r3 INT )
EXTERNAL ‘my_tpf_proc@mylibrary’;
This example illustrates how a TPF would get the maximum value for column two of the input
table, for internal optimization purposes.
my_tpf_describe(a_v4_extfn_proc_context *cntxt)
{
if( cntxt->current_state > EXTFNAPIV4_STATE_INITIAL ) {
a_sql_int32 max_value = 0;
a_sql_int32 ret = 0;
See also
• Query Processing States on page 121
• EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE (Set) on page 239
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Get) on page 211
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Set) on page 228
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Get) on page 212
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Set) on page 229
• Generic describe_column Errors on page 325
EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT (Get)
The EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT attribute sets a subset of
the values specified in an input column. Using this attribute in a describe_column_get
scenario returns an error.
Data Type
a_v4_extfn_col_subset_of_input
Description
Column values are a subset of the values specified in an input column.
Usage
This attribute can be set only.
Returns
Returns the error EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE.
See also
• EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT (Set) on page
240
• Generic describe_column Errors on page 325
• Query Processing States on page 121
*describe_column_set
The describe_column_set v4 API method sets UDF column-level properties on the
server.
Description
Column-level properties describe various characteristics about columns in the result set or
input tables in a TPF. For example, a UDF can tell the server that a column in its result set will
have only ten distinct values.
Declaration
a_sql_int32 (SQL_CALLBACK *describe_column_set)(
a_v4_extfn_proc_context *cntxt,
a_sql_uint32 arg_num,
a_sql_uint32 column_num,
a_v4_extfn_describe_udf_type describe_type,
const void *describe_buffer,
size_t describe_buffer_len );
Parameters
Parameter Description
cntxt The procedure context object for this UDF.
Returns
On success, returns the number of bytes written to the describe_buffer. If an error occurs, or
no property is retrieved, this function returns one of the generic describe_column errors.
See also
• *describe_column_get on page 209
EXTFNAPIV4_DESCRIBE_COL_NAME (Set)
The EXTFNAPIV4_DESCRIBE_COL_NAME attribute indicates a column name. Used in a
describe_column_set scenario.
Data Type
char[]
Description
The column name. This property is valid only for table arguments.
Usage
For argument 0, if the UDF sets this property, the server compares the value with the name of
the column supplied in the CREATE PROCEDURE statement. The comparison ensures that the
CREATE PROCEDURE statement has the same column name as expected by the UDF.
Returns
On success, returns the length of the column name.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
Annotation.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – set error returned if the
parameter is not a TABLE parameter.
• EXTFNAPIV4_DESCRIBE_ INVALID_ATTRIBUTE_VALUE – set error returned if
the length of input column name exceeds 128 characters or if the input column name and
column name stored in the catalog do not match.
Example
short desc_rc = 0;
char name[7] = ‘column1’;
// Verify that the procedure was created with the second column
of the result table as an int
if( ctx->current_state == EXTFNAPIV4_STATE_ANNOTATION ) {
desc_rc = ctx->describe_column_set( ctx, 0, 2,
EXTFNAPIV4_DESCRIBE_COL_NAME,
name,
sizeof(name) );
if( desc_rc < 0 ) {
// handle the error.
}
}
See also
• EXTFNAPIV4_DESCRIBE_COL_NAME (Get) on page 210
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Set) on page 228
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Get) on page 211
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_TYPE (Set)
The EXTFNAPIV4_DESCRIBE_COL_TYPE attribute indicates the data type of the column.
Used in a describe_column_set scenario.
Data Type
a_sql_data_type
Description
The data type of the column. This property is valid only for table arguments.
Usage
For argument zero, if the UDF sets this property, then the server compares the value with the
data type of the column supplied in the CREATE PROCEDURE statement. This allows the
UDF to ensure the CREATE PROCEDURE statement has the same data type as expected by the
UDF.
Returns
On success, returns the a_sql_data_type.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – Set error returned if the
describe buffer is not the size of a_sql_data_type.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – Set error returned if the state is not
Annotation.
• EXTFNAPIV4_DESCRIBE_ INVALID_ATTRIBUTE_VALUE – Set error returned if
the input data type and the data type stored in the catalog do not match,.
Example
short desc_rc = 0;
a_sql_data_type type = DT_INT;
// Verify that the procedure was created with the second column of
the result table as an int
if( ctx->current_state == EXTFNAPIV4_STATE_ANNOTATION ) {
See also
• Generic describe_column Errors on page 325
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Get) on page 211
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_WIDTH (Set)
The EXTFNAPIV4_DESCRIBE_COL_WIDTH attribute indicates the width of the column.
Used in a describe_column_set scenario.
Data Type
a_sql_uint32
Description
The width of a column. Column width is the amount of storage, in bytes, required to store a
value of the associated data type. This property is valid only for table arguments.
Usage
If the UDF sets this property, the server compares the value with the width of the column
supplied in the CREATE PROCEDURE statement. This allows the UDF to ensure the CREATE
PROCEDURE statement has the same column width as expected by the UDF.
Returns
On success, returns the sizeof(a_sql_uint32).
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the query
processing state is not Annotation.
• EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if
the input width and width stored in the catalog do not match.
See also
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Get) on page 212
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_SCALE (Set)
The EXTFNAPIV4_DESCRIBE_COL_SCALE attribute indicates the scale of the column. Used
in a describe_column_set scenario.
Data Type
a_sql_uint32
Description
The scale of a column. For arithmetic data types, parameter scale is the number of digits to the
right of the decimal point in a number. This property is valid only for table arguments.
Usage
If the UDF sets this property, the server compares the value with the scale of the column
supplied in the CREATE PROCEDURE statement. This allows the UDF to ensure the CREATE
PROCEDURE statement has the same column width as expected by the UDF. This property is
valid only for arithmetic data types.
Returns
On success, returns the sizeof(a_sql_uint32), or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – set error returned if the scale is not
available for the data type of the specified column.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the query
processing state is not Annotation.
• EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if
the input scale and scale stored in the catalog do not match.
Example
short desc_rc = 0;
a_sql_uint32 scale = 0;
See also
• EXTFNAPIV4_DESCRIBE_COL_SCALE (Get) on page 212
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_CAN_BE_NULL (Set)
The EXTFNAPIV4_DESCRIBE_COL_CAN_BE_NULL attribute indicates if the column can be
null. Used in a describe_column_set scenario.
Data Type
a_sql_byte
Description
True, if the column can be NULL. This property is valid only for table arguments. This
property is valid only for argument 0.
Usage
The UDF can set this property for a result table column if that column can be NULL. If the
UDF does not explicitly set this property, it is assumed that the column can be NULL. The
server can use this information during the Optimization state.
Returns
On success, returns the sizeof(a_sql_byte) if the attribute was set or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – returned if the attribute was
unavailable to set, which may happen if the column was uninvolved in the query.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
equal to OPTIMIZATION.
See also
• EXTFNAPIV4_DESCRIBE_COL_CAN_BE_NULL (Get) on page 213
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES (Set)
The EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES attribute describes the distinct
values for a column. Used in a describe_column_set scenario.
Data Type
a_v4_extfn_estimate
Description
The estimated number of distinct values for a column. This property is valid only for table
arguments.
Usage
The UDF can set this property if it knows how many distinct values a column can have in its
result table. The server uses this information during the Optimization state.
Returns
On success, returns the sizeof(a_v4_extfn_estimate), if it sets the value, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – returned if the attribute was
unavailable to set. This can happen if the column was not involved in the query.
On failure, returns:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe buffer is not the size of a_v4_extfn_estimate.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
equal to Optimization.
See also
• EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES (Get) on page 214
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_IS_UNIQUE (Set)
The EXTFNAPIV4_DESCRIBE_COL_IS_UNIQUE attribute indicates if the column is unique
in the table. Used in a describe_column_set scenario.
Data Type
a_sql_byte
Description
True, if the column is unique within the table. This property is valid only for table arguments.
Usage
The UDF can set this property if it knows the result table column value is unique. The server
uses this information during the Optimization state. The UDF can set this property only for
argument 0.
Returns
On success, returns the sizeof(a_sql_byte) or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – if the attribute was not available to
set. This can happen if the column was not involved in the query.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the query
processing state is not Optimization.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned if the
arg_num is not zero.
• EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if
the UDF attempts to set this attribute to a value other than 0 or 1.
See also
• Generic describe_column Errors on page 325
• EXTFNAPIV4_DESCRIBE_COL_IS_UNIQUE (Get) on page 216
EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT (Set)
The EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT attribute indicates if the column is
constant. Used in a describe_column_set scenario.
Data Type
a_sql_byte
Description
True, if the column is constant for the lifetime of the statement. This property is valid only for
input table arguments.
Usage
This is a read only property. All attempts to set it return
EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE.
Returns
• EXTFNAPIV4_DESCRIBE_INVALID ATTRIBUTE – this is a read-only property; all
attempts to set return this error.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned, if the state is not
Optimization.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned, if the
arg_num is not zero.
• EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned, if
the UDF attempts to set this attribute to a value other than 0 or 1.
See also
• EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT (Get) on page 217
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE (Set)
The EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE attribute indicates the constant
value of the column. Used in a describe_column_set scenario.
Data Type
an_extfn_value
Description
The value of the column, if it is constant for the statement lifetime. If
EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT for this column returns true, this value
is available. This property is valid only for table arguments.
Usage
This property is read-only.
Returns
• EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE – this is a read-only property; all
attempts to set return this error.
See also
• Generic describe_column Errors on page 325
• EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE (Get) on page 218
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER (Set)
The EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER attribute indicates if the
column in the result table is used by the consumer. Used in a describe_column_set
scenario.
Data Type
a_sql_byte
Description
Used either to determine whether a column in the result table is used by the consumer, or to
indicate that a column in an input is not needed. Valid for table arguments. Allows the user to
set or retrieve information about a single column, whereas the similar attribute
EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS sets or retrieves
information about all columns in a single call.
Usage
The UDF sets EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER on columns in an
input table to inform the producer that it does not need values for the column.
Returns
On success, returns the sizeof(a_sql_byte) or:
When this TPF runs, it is beneficial for the server to know if column y is used by this TPF. If the
TPF does not need y, the server can use this knowledge for optimization and does not send this
column information to the TPF.
my_tpf_describe(a_v4_extfn_proc_context *cntxt)
{
if( cntxt->current_state == EXTFNAPIV4_STATE_OPTIMIZATION ) {
a_sql_byte col_is_used = 0;
a_sql_int32 ret = 0;
}
}
See also
• EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER (Get) on page 219
• Generic describe_column Errors on page 325
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE (Set)
The EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE attribute indicates the minimum
value for the column. Used in a describe_column_set scenario.
Data Type
an_extfn_value
Description
The minimum value a column can have, if available. Only valid for argument 0.
Usage
The UDF can set EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE, if it knows what
the minimum data value of the column is. The server can use this information during
optimization.
The UDF can use EXTFNAPIV4_DESCRIBE_COL_TYPE to determine the data type of the
column, and EXTFNAPIV4_DESCRIBE_COL_WIDTH to determine the storage
requirements of the column, to provide an equivalently sized buffer to hold the value to set.
Returns
On success, returns the describe_buffer_length, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – if the attribute cannot be set.
Returned if the column was not involved in the query or the minimum value was not
available for the requested column.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned, if the
describe buffer is not large enough to hold the minimum value.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned, if the state is not
equal to Optimization.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned, if the
arg_num is not 0.
Example
The PROCEDURE definition and UDF code fragment that implements the
_describe_extfn callback API function:
CREATE PROCEDURE my_tpf( col_char char(10), col_table TABLE( c1 INT,
c2 INT ) )
RESULTS ( r1 INT, r2 INT, r3 INT )
EXTERNAL ‘my_tpf_proc@mylibrary’;
This example shows a TPF where it is useful to the server (or to another TPF that takes the
result of this TPF as input) to know the minimum value of result set column one. In this
instance, the minimum output value of column one is 27.
my_tpf_describe(a_v4_extfn_proc_context *cntxt)
{
if( cntxt->current_state == EXTFNAPIV4_STATE_OPTIMIZATION ) {
a_sql_int32 min_value = 27;
a_sql_int32 ret = 0;
// Tell the server what the minimum value of the first column
// of our result set will be.
See also
• Query Processing States on page 121
• EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE (Get) on page 221
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Set) on page 228
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Get) on page 211
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Set) on page 229
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Get) on page 212
• Generic describe_column Errors on page 325
EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE (Set)
The EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE attribute indicates the maximum
value for the column. Used in a describe_column_set scenario.
Data Type
an_extfn_value
Description
The maximum value for a column. This property is valid only for argument 0 and table
arguments.
Usage
The UDF can set EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE, if it knows what
the maximum data value of the column is. The server can use this information during
optimization.
The UDF can use EXTFNAPIV4_DESCRIBE_COL_TYPE to determine the data type of the
column, and EXTFNAPIV4_DESCRIBE_COL_WIDTH to determine the storage
requirements of the column, to provide an equivalently sized buffer to hold the value to set.
describe_buffer_length is the sizeof() this buffer.
Returns
On success, returns the describe_buffer_length, if the value was set, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – if the attribute could not be set.
Returned if the column was not involved in the query or the maximum value was not
available for the requested column.
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned, if the
describe buffer is not large enough to hold the maximum value.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – Set error returned, if the query
processing state is not equal to Optimization.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned, if the
arg_num is not 0.
Example
The PROCEDURE definition and and UDF code fragment that implements the
_describe_extfn callback API function:
This example shows a TPF where it is useful to the server (or to another TPF that takes the
result of this TPF as input) to know the maximum value of result set column one. In this
instance, the maximum output value of column one is 500000.
my_tpf_describe(a_v4_extfn_proc_context *cntxt)
{
if( cntxt->current_state == EXTFNAPIV4_STATE_OPTIMIZATION ) {
a_sql_int32 max_value = 500000;
a_sql_int32 ret = 0;
// Tell the server what the maximum value of the first column
// of our result set will be.
}
}
See also
• Query Processing States on page 121
• EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE (Get) on page 223
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Get) on page 211
• EXTFNAPIV4_DESCRIBE_COL_TYPE (Set) on page 228
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Get) on page 212
• EXTFNAPIV4_DESCRIBE_COL_WIDTH (Set) on page 229
• Generic describe_column Errors on page 325
EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT (Set)
The EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT attribute sets a subset of
the values specified in an input column. Used in a describe_column_set scenario.
Data Type
a_v4_extfn_col_subset_of_input
Description
Column values are a subset of the values specified in an input column.
Usage
Setting this describe attribute informs the query optimizer that the indicated column values are
a subset of those values specified in an input column. For example, consider a filter TPF that
consumes a table and filters out rows based on a function. In such a case, the return table is a
subset of the input table. Setting
EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT for the filter TPF optimizes
the query.
Returns
On success, returns the sizeof(a_v4_extfn_col_subset_of_input).
On failure, returns one of the generic describe_column errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
buffer length is less than sizeof (a_v4_extfn_col_subset_of_input).
• EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if
the column index of the source table is out of range.
• EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE – set error returned if the column
subset_of_input is set on is not aplicable (for example, if the column is not in the
select list).
• EXTFNAPIV4_DESCRIBE_INVAILD_STATE – set error returned if the query
processing state is not Optimization.
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
buffer length is zero.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned if called on a
parameter other than the return table.
Example
a_v4_extfn_col_subset_of_input colMap;
colMap.source_table_parameter_arg_num = 4;
colMap.source_column_number = i;
See also
• EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT (Get) on page 225
• Generic describe_column Errors on page 325
• Query Processing States on page 121
*describe_parameter_get
The describe_parameter_get v4 API method gets UDF parameter properties from
the server.
Declaration
a_sql_int32 (SQL_CALLBACK *describe_parameter_get)(
a_v4_extfn_proc_context *cntxt,
a_sql_uint32 arg_num,
a_v4_extfn_describe_udf_type describe_type,
const void *describe_buffer,
size_t describe_buffer_len );
Parameters
Parameter Description
cntxt The procedure context object.
Returns
On success, returns 0 or the number of bytes written to the describe_buffer. A value of 0
indicates that the server was unable to get the attribute, but no error condition occurred. If an
error occurred, or no property was retrieved, this function returns one of the generic
describe_parameter errors.
EXTFNAPIV4_DESCRIBE_PARM_WIDTH,
EXTFNAPIV4_DESCRIBE_PARM_SCALE,
EXTFNAPIV4_DESCRIBE_PARM_CAN_BE_NULL,
EXTFNAPIV4_DESCRIBE_PARM_DISTINCT_VALUES,
EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT,
EXTFNAPIV4_DESCRIBE_PARM_CONSTANT_VALUE,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_COLUMNS,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_ROWS,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_ORDERBY,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS,
} a_v4_extfn_describe_parm_type;
Data Type
char[]
Description
The name of a parameter to a UDF.
Usage
Gets the parameter name as defined in the CREATE PROCEDURE statement. Invalid for
parameter 0.
Returns
On success, returns the length of the parameter name.
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not large enough to hold the name.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the
parameter is the result table.
See also
• EXTFNAPIV4_DESCRIBE_PARM_NAME Attribute (Set) on page 262
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_data_type
Description
The data type of a parameter to a UDF.
Usage
Gets the data type of the parameter as defined in the CREATE PROCEDURE statement.
Returns
On success, returns sizeof(a_sql_data_type).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not the sizeof(a_sql_data_type).
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Set) on page 263
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_uint32
Description
The width of a parameter to a UDF. EXTFNAPIV4_DESCRIBE_PARM_WIDTH applies
only to scalar parameters. Parameter width is the amount of storage, in bytes, required to store
a parameter of the associated data type.
• Fixed length data types – the bytes required to store the data.
• Variable length data types – the maximum length.
• LOB data types – the amount of storage required to store a handle to the data.
• TIME data types – the amount of storage required to store the encoded time.
Usage
Gets the width of the parameter as defined in the CREATE PROCEDURE statement.
Returns
On success, returns the sizeof(a_sql_uint32).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the
specified parameter is a TABLE parameter. This includes parameter 0, or parameter n
where n is an input table.
Example
Sample procedure definition:
}
}
See also
• EXTFNAPIV4_DESCRIBE_PARM_WIDTH Attribute (Set) on page 264
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_uint32
Description
The scale of a parameter to a UDF. For arithmetic data types, parameter scale is the number of
digits to the right of the decimal point in a number.
This attribute is not valid for:
• non-arithmetic data types
• TABLE parameters
Usage
Gets the scale of the parameter as defined in the CREATE PROCEDURE statement.
Returns
On success, returns the size of (a_sql_uint32).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the
specified parameter is a TABLE parameter. This includes parameter 0, or parameter n
where n is an input table.
Example
Sample _describe_extfn API function code fragment that gets the scale of parameter
1:
if( cntxt->current_state > EXTFNAPIV4_STATE_ANNOTATION ) {
a_sql_uint32 scale = 0;
a_sql_int32 ret = 0;
}
}
See also
• EXTFNAPIV4_DESCRIBE_PARM_SCALE Attribute (Set) on page 265
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_byte
Description
True, if the value of a parameter can be NULL at the time of execution. For a TABLE
parameter or parameter 0, the value is false.
Usage
Gets whether or not the specified parameter can be null during query execution.
Returns
On success, returns the sizeof(a_sql_byte).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – Get error returned if the
describe_buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – Get error returned if the query
processing phase is not greater than Plan Building.
Procedure Definition
Sample procedure definition used by the example queries in this topic:
CREATE PROCEDURE my_udf(IN p INT)
RESULT (x INT)
EXTERNAL NAME ‘my_udf@myudflib’;
Data Type
a_v4_extfn_estimate
Description
Returns the estimated number of distinct values across all invocations. valid only for scalar
parameters.
Usage
If this information is available, the UDF returns the estimated number of distinct values with
100% confidence. If the information is not available, the UDF returns an estimate of 0 with 0%
confidence.
Returns
On success, returns the sizeof(a_v4_extfn_estimate).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not the size of a_v4_extfn_estimate.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the
parameter is a TABLE parameter.
Example
Sample _describe_extfn API function code fragment:
if( ctx->current_state >= EXTFNAPIV4_STATE_ANNOTATION ) {
desc_est.value = 0.0;
desc_est.confidence = 0.0;
See also
• EXTFNAPIV4_DESCRIBE_PARM_DISTINCT_VALUES Attribute (Set) on page
267
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Get) on page 244
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_byte
Description
True, if the parameter is a constant for the statement. Valid only for scalar parameters.
Usage
Returns 0 if the value of the specified parameter is not a constant; returns 1 if the value of the
specified parameter is a constant.
Returns
On success, returns the sizeof(a_sql_byte).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the
parameter is a TABLE parameter.
Example
Sample _describe_extfn API function code fragment:
if( ctx->current_state >= EXTFNAPIV4_STATE_ANNOTATION ) {
desc_rc = ctx->describe_parameter_get( ctx,
1,
EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT,
&desc_byte, sizeof( a_sql_byte ) );
}
See also
• EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT Attribute (Set) on page 267
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Set) on page 263
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
an_extfn_value
Description
The value of the parameter if it is known at describe time. Valid only for scalar parameters.
Usage
Returns the value of the parameters.
Returns
On success, returns the sizeof(an_extfn_value) if the value is available, or:
• EXTFNAPIV4_DESCRIBE_NOT_AVILABLE – Value returned if the value is not
constant.
On failure, returns one of the generic describe_parameter errors or:
Example
Sample _describe_extfn API function code fragment:
if( ctx->current_state >= EXTFNAPIV4_STATE_ANNOTATION ) {
a_sql_int32 desc_rc;
desc_rc = ctx->describe_parameter_get( ctx,
1,
EXTFNAPIV4_DESCRIBE_PARM_CONSTANT_VALUE,
&arg,
sizeof( an_extfn_value ) );
}
See also
• EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT Attribute (Set) on page 267
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Get) on page 244
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_uint32
Description
The number of columns in the table. Only valid for argument 0 and table arguments.
Usage
Returns the number of columns in the specified table argument. Argument 0 returns the
number of columns in the result table.
Returns
On success, returns the sizeof(a_sql_uint32).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not the size of size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Initial.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – get error returned if the
parameter is not a TABLE parameter.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_COLUMNS Attribute (Set) on
page 268
• Query Processing States on page 121
Data Type
a_v4_extfn_estimate
Description
The estimated number of rows in the table. Only valid for argument 0 and table arguments.
Usage
Returns the estimated number of rows in the specified table argument or result set with a
confidence of 100%.
Returns
On success, returns the size of a_v4_extfn_estimate.
On failure, returns one of the generic describe_parameter errors or:
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_ROWS Attribute (Set) on page
269
• Query Processing States on page 121
Data Type
a_v4_extfn_orderby_list
Description
The order of rows in the table. This property is only valid for argument 0 and table arguments.
Usage
This attribute allows the UDF code to:
• Determine if the input TABLE parameter has been ordered
• Declare that the result set is ordered
If the parameter number is 0, then the attribute refers to the outbound result set. If the
parameter is > 0 and the parameter type is a table then the attribute refers to the input TABLE
parameter.
The order is specified by the a_v4_extfn_orderby_list, which is a structure
supporting a list of column ordinals and their associated ascending or descending property. If
the UDF sets the order by property for the outbound result set, the server is then able to
perform order by optimizations. For example, if the UDF produced ascending order on the
first result set column, the server will eliminate a redundant order by request on the same
column.
If the UDF does not set the orderby property on the outbound result set, the server assumes the
data is not ordered.
If the UDF sets the orderby property on the input TABLE parameter, the server guarantees data
ordering for the input data. In this scenario, the UDF describes to the server that the input data
must be ordered. If the server detects a runtime conflict it raises a SQL exception. For
example, when the UDF describes that the first column of the input TABLE parameter must
have ascending order and the SQL statement contains a descending clause, the server raises a
SQL exception.
In the event that the SQL did not contain an ordering clause, the server automatically adds the
ordering to ensure that input TABLE parameter is ordered as required.
Returns
If successful, returns the number of bytes copied from a_v4_extfn_orderby_list.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_ORDERBY Attribute (Set) on page 270
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY (Get)
The EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY attribute indicates that
the UDF requires partitioning. Used in a describe_parameter_get scenario.
Data Type
a_v4_extfn_column_list
Description
UDF developers use EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY to
programmatically declare that the UDF requires partitioning before invocation can proceed.
Usage
The UDF can inquire to the partition to enforce it, or to dynamically adapt the partitioning. It is
the UDF's responsibility to allocate the a_v4_extfn_column_list, taking into consideration the
total number of columns in the input table, and sending that data to the server.
Returns
On success, returns the size of a_v4_extfn_column_list. This value is equal to:
sizeof(a_v4_extfn_column_list) + sizeof(a_sql_uint32) *
number_of_partition_columns
Example
void UDF_CALLBACK my_tpf_proc_describe( a_v4_extfn_proc_context
*ctx )
{
if( ctx->current_state == EXTFNAPIV4_STATE_OPTIMIZATION ) {
a_sql_uint32 col_count = 0;
a_sql_uint32 buffer_size = 0;
a_v4_extfn_column_list *clist = NULL;
clist->number_of_columns = 0;
clist->column_indexes[0] = 0;
clist->column_indexes[1] = 0;
clist->column_indexes[2] = 0;
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY (Set) on page 272
Data Type
a_sql_byte
Description
Indicates that the consumer wants to rewind an input table. Valid only for table input
arguments. By default, this property is false.
Usage
The UDF queries this property to retrieve the true/false value.
Returns
On success, returns sizeof(a_sql_byte).
On failure, returns one of the generic describe_parameter errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the phase is not
Optimization or Plan Building.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the UDF
attempts to get this attribute on parameter 0.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – get error returned if the
UDF attempts to get this attribute on a parameter that is not a table.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND Attribute (Set) on
page 273
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND Attribute (Set) on page
275
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND Attribute (Get) on page
259
• _rewind_extfn on page 323
• Query Processing States on page 121
Data Type
a_sql_byte
Description
Indicates whether a producer can support rewind. Valid only for table arguments.
You must also provide an implementation of the rewind table callback (_rewind_extfn() ) if
you plan on setting DESCRIBE_PARM_TABLE_HAS_REWIND to true. The server will
fail to execute the UDF if the callback method is not provided.
Usage
The UDF asks if a table input argument supports rewind. As a prerequisite, the UDF must
request rewind using DESCRIBE_PARM_TABLE_REQUEST_REWIND before you can use
this property.
Returns
On success, returns sizeof(a_sql_byte).
On failure, returns one of the generic describe_parameter errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error error returned if the query
processing phase is not greater than Annotation.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – get error returned if the
UDF attempts to get this attribute on a parameter that is not a table.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the UDF
attempts to get this attribute on the result table.
• Optimization phase
• Plan Building phase
• Execution phase
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND Attribute (Get) on
page 258
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND Attribute (Set) on
page 273
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND Attribute (Set) on page
275
• _rewind_extfn on page 323
• Query Processing States on page 121
Data Type
a_v4_extfn_column_list
Description
The list of output table columns that are not going to be consumed by the server or the UDF.
For the output TABLE parameter, the UDF normally produces the data for all the columns, and
the server consumes all the columns. The same holds true for the input TABLE parameter
where the server normally produces the data for all the columns, and the UDF consumes all the
columns.
However, in some cases the server, or the UDF, may not consume all the columns. The best
practice in such a case is for the UDF to perform a GET for the output table on the describe
attribute EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS. This action
queries the server for the list of output table columns that are not going to be consumed by the
server. The list can then be used by the UDF when populating the column data for the output
table; that is, the UDF does not attemp to populate data for unused columns.
In summary, for the output table the UDF polls the list of unused columns. For the input table,
the UDF pushes the list of unused columns.
Usage
The UDF asks the server if all the columns of the output table are going to be used. The UDF
must allocate a a_v4_extfn_column_list that includes all the columns of the output
table, and then must pass it to the server. The server then marks all the unprojected column
ordinals as 1. The list returned by the server can be used while producing the data.
Returns
On success, returns the size of the column list: sizeof(a_v4_extfn_column_list)
+ sizeof(a_sql_uint32) * number result columns.
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the query
processing phase is not greater than Plan Building.
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe_buffer is not large enough to hold the returned list.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the UDF
attempts to get this attribute on an input table.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – get error returned if the
UDF attempts to get this attribute on a parameter that is not a table.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS Attribute (Set) on
page 276
*describe_parameter_set
The describe_parameter_set v4 API method sets properties about a single parameter
to the UDF.
Declaration
a_sql_int32 (SQL_CALLBACK *describe_parameter_set)(
a_v4_extfn_proc_context *cntxt,
a_sql_uint32 arg_num,
a_v4_extfn_describe_udf_type describe_type,
const void *describe_buffer,
size_t describe_buffer_len );
Parameters
Parameter Description
cntxt The procedure context object.
Parameter Description
describe_type A selector indicating what property to set.
Returns
On success, returns 0 or the number of bytes written to the describe_buffer. A value of 0
indicates that the server was unable to set the attribute, but no error condition occurred. If an
error occurred, or no property was retrieved, this function returns one of the generic
describe_parameter errors.
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_COLUMNS,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_ROWS,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_ORDERBY,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS,
} a_v4_extfn_describe_parm_type;
Data Type
char[]
Description
The name of a parameter to a UDF.
Usage
If the UDF sets this property, the server compares the value with the name of the parameter
supplied in the CREATE PROCEDURE statement. If the two values do not match, the server
returns an error. This allows the UDF to ensure the CREATE PROCEDURE statement has the
same parameter names as the UDF is expecting.
Returns
On success, returns the length of the parameter name.
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
equal to Annotation.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned if the
parameter is the result table.
• EXTFNAPI4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if the
UDF tries to reset the name.
See also
• EXTFNAPIV4_DESCRIBE_PARM_NAME Attribute (Get) on page 243
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_data_type
Description
The data type of a parameter to a UDF.
Usage
When the UDF sets this property, the server compares the value to the parameter type supplied
in the CREATE PROCEDURE statement. If the two values do not match, the server returns an
error. This check ensures that the CREATE PROCEDURE statement has the same parameter
data types that the UDF expects.
Returns
On success, returns sizeof(a_sql_data_type).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe_buffer is not the sizeof(a_sql_data_type).
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the query
processing state is not equal to Annotation.
• EXTFNAPI4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if the
UDF tries to set the datatype of a parameter to something other than what it is already
defined as.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Get) on page 244
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_uint32
Description
The width of a parameter to a UDF. EXTFNAPIV4_DESCRIBE_PARM_WIDTH applies
only to scalar parameters. Parameter width is the amount of storage, in bytes, required to store
a parameter of the associated data type.
• Fixed length data types – the bytes required to store the data.
• Variable length data types – the maximum length.
• LOB data types – the amount of storage required to store a handle to the data.
• TIME data types – the amount of storage required to store the encoded time.
Usage
This is a read-only property. The width is derived from the associated column data type. Once
the data type is set, you cannot change the width.
Returns
On success, returns the sizeof(a_sql_uint32).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the query
processing state is not equal to Annotation.
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe_buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned if the
specified parameter is a TABLE parameter. This includes parameter 0, or parameter n,
where n is an input table.
• EXTFNAPI4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if the
UDF tries to reset the parameter width.
See also
• EXTFNAPIV4_DESCRIBE_PARM_WIDTH Attribute (Get) on page 245
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_uint32
Description
The scale of a parameter to a UDF. For arithmetic data types, parameter scale is the number of
digits to the right of the decimal point in a number.
This attribute is invalid for:
• Nonarithmetic data types
• TABLE parameters
Usage
This is a read-only property. The scale is derived from the associated column data type. Once
the data type is set, you cannot change the scale.
Returns
On success, returns sizeof(a_sql_uint32).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe_buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
Annotation.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned if the
specified parameter is a TABLE parameter. This includes parameter 0, or parameter n,
where n is an input table.
See also
• EXTFNAPIV4_DESCRIBE_PARM_SCALE Attribute (Get) on page 246
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_byte
Description
True, if the value of a parameter can be NULL at the time of execution. For a TABLE
parameter or parameter 0, the value is false.
Usage
This is a read-only property.
Returns
This is a read-only property, so all attempts to set result in an
EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE error.
Data Type
a_v4_extfn_estimate
Description
Returns the estimated number of distinct values across all invocations. valid only for scalar
parameters.
Usage
This is a read-only property.
Returns
This is a read-only property; all attempts to set result in an
EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE error.
See also
• EXTFNAPIV4_DESCRIBE_PARM_DISTINCT_VALUES Attribute (Get) on page
250
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Get) on page 244
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
Data Type
a_sql_byte
Description
True, if the parameter is a constant for the statement. Valid only for scalar parameters.
Usage
This is a read-only property.
Returns
This is a read-only property; all attempts to set result in an
EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE error.
See also
• EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT Attribute (Get) on page 251
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Set) on page 263
• Generic describe_parameter Errors on page 326
• Query Processing States on page 121
• EXTFNAPIV4_DESCRIBE_PARM_CONSTANT_VALUE Attribute (Get) on page
252
• EXTFNAPIV4_DESCRIBE_PARM_TYPE Attribute (Get) on page 244
Data Type
an_extfn_value
Description
The value of the parameter if it is known at describe time. Valid only for scalar parameters.
Usage
This is a read-only property.
Returns
This is a read-only property; all attempts to set result in an
EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE error.
Data Type
a_sql_uint32
Description
The number of columns in the table. Only valid for argument 0 and table arguments.
Usage
If the UDF sets this property, the server compares the value with the name of the parameter
supplied in the CREATE PROCEDURE statement. If the two values do not match, the server
returns an error. This allows the UDF to ensure the CREATE PROCEDURE statement has the
same parameter names as the UDF is expecting.
Returns
On success, returns the sizeof(a_sql_uint32).
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe_buffer is not the size of size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
ANNOTATION.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – set error returned if the
parameter is not a TABLE parameter.
• EXTFNAPI4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if the
UDF tries to reset the number of columns of the specified table.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_COLUMNS Attribute (Get) on
page 253
• Query Processing States on page 121
Data Type
a_sql_a_v4_extfn_estimate
Description
The estimated number of rows in the table. Only valid for argument 0 and table arguments.
Usage
The UDF sets this property for argument 0 if it estimates the number of rows in the result set.
The server uses the estimate during optimization to make query processing decisions. You
cannot set this value for an input table.
If you do not set a value, the server defaults to the number of rows specified by the
DEFAULT_TABLE_UDF_ROW_COUNT option.
Returns
On success, returns a_v4_extfn_estimate.
On failure, returns one of the generic describe_parameter errors or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe_buffer is not the size of a_v4_extfn_estimate.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
Optimization.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – get error returned if the
parameter is not a TABLE parameter.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – get error returned if the
TABLE parameter is not the result table.
• EXTFNAPI4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – get error returned if the
UDF tries to reset the number of columns of the specified table.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_ROWS Attribute (Get) on page
254
• Query Processing States on page 121
Data Type
a_v4_extfn_orderby_list
Description
The order of rows in the table. This property is only valid for argument 0 and table arguments.
Usage
This attribute allows the UDF code to:
• Determine if the input TABLE parameter has been ordered
• Declare that the result set is ordered.
If the parameter number is 0, then the attribute refers to the outbound result set. If the
parameter is > 0 and the parameter type is a table then the attribute refers to the input TABLE
parameter.
The order is specified by the a_v4_extfn_orderby_list, which is a structure
supporting a list of column ordinals and their associated ascending or descending property. If
the UDF sets the order by property for the outbound result set, the server is then able to
perform order by optimizations. For example, if the UDF produced ascending order on the
first result set column, the server will eliminate a redundant order by request on the same
column.
If the UDF does not set the orderby property on the outbound result set, the server assumes the
data is not ordered.
If the UDF sets the orderby property on the input TABLE parameter, the server guarantees data
ordering for the input data. In this scenario, the UDF describes to the server that the input data
must be ordered. If the server detects a runtime conflict it raises a SQL exception. For
example, when the UDF describes that the first column of the input TABLE parameter must
have ascending order and the SQL statement contains a descending clause, the server raises a
SQL exception.
In the event that the SQL did not contain an ordering clause, the server automatically adds the
ordering to ensure that input TABLE parameter is ordered as required.
Returns
If successful, returns the number of bytes copied from a_v4_extfn_orderby_list.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_ORDERBY Attribute (Get) on page 255
• Query Processing States on page 121
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY (Set)
The EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY attribute indicates that
the UDF requires partitioning. Used in a describe_parameter_set scenario.
Data Type
a_v4_extfn_column_list
Description
UDF developers use EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY to
programmatically declare that the UDF requires partitioning before invocation can proceed.
Usage
The UDF can inquire to the partition to enforce it, or to dynamically adapt the partitioning.
The UDF must allocate the a_v4_extfn_column_list, taking into consideration the total
number of columns in the input table, and sending that data to the server.
Returns
On success, returns the size of a_v4_extfn_column_list. This value is equal to:
sizeof(a_v4_extfn_column_list) + sizeof(a_sql_uint32) *
number_of_partition_columns
Example
void UDF_CALLBACK my_tpf_proc_describe( a_v4_extfn_proc_context
*ctx )
{
if( ctx->current_state == EXTFNAPIV4_STATE_ANNOTATION ) {
a_sql_int32 rc = 0;
a_v4_extfn_column_list pbcol =
{ 1, // 1 column in the partition by list
2 }; // column index 2 requires partitioning
if( rc == 0 ) {
ctx->set_error( ctx, 17000,
“Runtime error, unable set partitioning requirements for
column.” );
}
}
}
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY (Get) on page 256
• Generic describe_parameter Errors on page 326
• V4 API describe_parameter and
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY on page 141
• Parallel TPF PARTITION BY Examples Using
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY on page 143
• Query Processing States on page 121
• Partitioning Input Data on page 140
Data Type
a_sql_byte
Description
Indicates that the consumer wants to rewind an input table. Valid only for table input
arguments. By default, this property is false.
Usage
If the UDF requires input table rewind capability, the UDF must set this property during
Optimization.
Returns
On success, returns sizeof(a_sql_byte).
On failure, returns one of the generic describe_parameter errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe_buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
equal to Optimization.
Example
In this example, when the function my_udf_describe is called during the Optimization state,
the call to describe_parameter_set informs the producer of the table input parameter
1 that a rewind may be required.
Sample procedure definition:
CREATE PROCEDURE my_udf(IN t TABLE(c1 INT))
RESULT (x INT)
EXTERNAL NAME ‘my_udf@myudflib’;
Sample _describe_extfn API function code fragment:
my_udf_describe(a_v4_extfn_proc_context *cntxt)
{
if( cntxt->current_state == EXTFNAPIV4_STATE_OPTIMIZATION ) {
a_sql_byte rewind_required = 1;
a_sql_int32 ret = 0;
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND Attribute (Get) on
page 258
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND Attribute (Set) on page
275
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND Attribute (Get) on page
259
• _rewind_extfn on page 323
Data Type
a_sql_byte
Description
Indicates whether a producer can support rewind. Valid only for table arguments.
You must also provide an implementation of the rewind table callback (_rewind_extfn() ), if
you plan on setting DESCRIBE_PARM_TABLE_HAS_REWIND to true. The server cannot
execute the UDF if you do not provide the callback method.
Usage
A UDF sets this property during the Optimization state if it can provide rewind capability for
its result table at no cost. If it is expensive for the UDF to provide rewind, do not set this
property, or set it to 0. If set to 0, the server provides rewind support.
Returns
On success, returns sizeof(a_sql_byte).
On failure, returns one of the generic describe_parameter errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if the
describe_buffer is not the size of a_sql_byte.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – set error returned if the state is not
equal to Optimization.
• EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER – set error returned if the
UDF attempts to set this attribute on a parameter that is not a table.
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned if the
specified argument is not the result table.
• EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if
the UDF attempts to set this attribute to a value other than 0 or 1.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND Attribute (Get) on
page 258
Data Type
a_v4_extfn_column_list
Description
The list of output table columns that are not going to be consumed by the server or the UDF.
For the output TABLE parameter, the UDF normally produces the data for all the columns, and
the server consumes all the columns. The same holds true for the input TABLE parameter
where the server normally produces the data for all the columns, and the UDF consumes all the
columns.
However, in some cases the server, or the UDF, may not consume all the columns. The best
practice in such a case is that the UDF performs a GET for the output table on the describe
attribute EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS. This action
queries the server for the list of output table columns which are not going to be consumed by
the server. The list can then be used by the UDF when populating the column data for the
output table; that is, the UDF skips populating data for unused columns.
In summary, for the output table the UDF polls the list of unused columns. For the input table,
the UDF pushes the list of unused columns.
Usage
The UDF sets this property during Optimization if it is not going to use certain columns of the
input TABLE parameter. The UDF must allocate a a_v4_extfn_column_list that
includes all the columns of the output table, and then must pass it to the server. The server then
marks all the un-projected column ordinals as 1. The server copies the list into its internal data
structure.
Returns
On success, returns the size of the column list: sizeof(a_v4_extfn_column_list)
+ sizeof(a_sql_uint32) * number result columns.
On failure, returns one of the generic describe_parameter errors or:
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS Attribute (Get)
on page 260
*describe_udf_get
The describe_udf_get v4 API method gets UDF properties from the server.
Declaration
a_sql_int32 (SQL_CALLBACK *describe_udf_get)(
a_v4_extfn_proc_context *cntxt,
a_v4_extfn_describe_udf_type describe_type,
void *describe_buffer,
size_t describe_buffer_len );
Parameters
Parameter Description
cntxt The procedure context object for this UDF.
Returns
On success, returns 0 or the number of bytes written to the describe_buffer. A value of 0
indicates that the server was unable to get the attribute but no error condition occurred. If an
error occurred, or no property was retrieved, this function returns one of the generic
describe_udf errors.
See also
• *describe_udf_set on page 279
• Generic describe_udf Errors on page 326
Data Type
a_sql_uint32
Description
The number of parameters supplied to the UDF.
Usage
Gets the number of parameters as defined in the CREATE PROCEDURE statement.
Returns
On success, returns the sizeof(a_sql_uint32).
On failure, returns one of the generic describe_udf errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – get error returned if the
describe buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – get error returned if the phase is not
greater than Initial.
See also
• EXTFNAPIV4_DESCRIBE_UDF_NUM_PARMS Attribute (Set) on page 280
• Generic describe_udf Errors on page 326
• Query Processing States on page 121
*describe_udf_set
The describe_udf_set v4 API method sets UDF properties on the server.
Declaration
a_sql_int32 (SQL_CALLBACK *describe_udf_set)(
a_v4_extfn_proc_context *cntxt,
a_v4_extfn_describe_udf_type describe_type,
const void *describe_buffer,
size_t describe_buffer_len );
Parameters
Parameter Description
cntxt The procedure context object for this UDF.
Returns
On success, returns the number of bytes written to the describe_buffer. If an error occurs, or
no property is retrieved, this function returns one of the generic describe_udf errors.
If an error occurs, or no property is retrieved, this function returns one of the generic
describe_udf errors, or:
• EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER – set error returned if any of the
cntxt or describe_buffer arguments are NULL or if describe_buffer_length is 0.
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – set error returned if there
is a discrepancy between the requested attribute’s size and the supplied
describe_buffer_length.
See also
• *describe_udf_get on page 277
• Generic describe_udf Errors on page 326
EXTFNAPIV4_DESCRIBE_UDF_LAST
} a_v4_extGetfn_describe_udf_type;
Data Type
a_sql_uint32
Description
The number of parameters supplied to the UDF.
Usage
If the UDF sets this property, the server compares the value with the number of parameters
supplied in the CREATE PROCEDURE statement. If the two values do not match, the server
returns a SQL error. This allows the UDF to ensure the CREATE PROCEDURE statement has
the same number of parameters expected by the UDF.
Returns
On success, returns the sizeof(a_sql_uint32).
On failure, returns one of the generic describe_udf errors, or:
• EXTFNAPIV4_DESCRIBE_BUFFER_SIZE_MISMATCH – Set error returned if the
describe buffer is not the size of a_sql_uint32.
• EXTFNAPIV4_DESCRIBE_INVALID_STATE – Set error returned if the state is not
equal to Annotation.
• EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE – set error returned if
the UDF tries to reset the parameter datatype.
See also
• EXTFNAPIV4_DESCRIBE_UDF_NUM_PARMS Attribute (Get) on page 278
• Generic describe_udf Errors on page 326
• Query Processing States on page 121
Implementation
typedef enum a_v4_extfn_describe_col_type {
EXTFNAPIV4_DESCRIBE_COL_NAME,
EXTFNAPIV4_DESCRIBE_COL_TYPE,
EXTFNAPIV4_DESCRIBE_COL_WIDTH,
EXTFNAPIV4_DESCRIBE_COL_SCALE,
EXTFNAPIV4_DESCRIBE_COL_CAN_BE_NULL,
EXTFNAPIV4_DESCRIBE_COL_DISTINCT_VALUES,
EXTFNAPIV4_DESCRIBE_COL_IS_UNIQUE,
EXTFNAPIV4_DESCRIBE_COL_IS_CONSTANT,
EXTFNAPIV4_DESCRIBE_COL_CONSTANT_VALUE,
EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUMER,
EXTFNAPIV4_DESCRIBE_COL_MINIMUM_VALUE,
EXTFNAPIV4_DESCRIBE_COL_MAXIMUM_VALUE,
EXTFNAPIV4_DESCRIBE_COL_VALUES_SUBSET_OF_INPUT,
EXTFNAPIV4_DESCRIBE_COL_LAST
} a_v4_extfn_describe_col_type;
Members Summary
Member Description
EXTFNAPIV4_DESCRIBE_COL_NAME Column name (valid identifier).
Member Description
EXTFNAPIV4_DESCRIBE_COL_IS_USED_BY_CONSUM- True, if column is needed by the
ER consumer of the table.
Implementation
typedef enum a_v4_extfn_describe_parm_type {
EXTFNAPIV4_DESCRIBE_PARM_NAME,
EXTFNAPIV4_DESCRIBE_PARM_TYPE,
EXTFNAPIV4_DESCRIBE_PARM_WIDTH,
EXTFNAPIV4_DESCRIBE_PARM_SCALE,
EXTFNAPIV4_DESCRIBE_PARM_CAN_BE_NULL,
EXTFNAPIV4_DESCRIBE_PARM_DISTINCT_VALUES,
EXTFNAPIV4_DESCRIBE_PARM_IS_CONSTANT,
EXTFNAPIV4_DESCRIBE_PARM_CONSTANT_VALUE,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_COLUMNS,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_NUM_ROWS,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_ORDERBY,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_PARTITIONBY,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND,
EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COLUMNS,
EXTFNAPIV4_DESCRIBE_PARM_LAST
} a_v4_extfn_describe_parm_type;
Members Summary
Member Description
EXTFNAPIV4_DESCRIBE_PARM_NAME Parameter name (valid iden-
tifier).
These selectors can retrieve or set properties of a TABLE parameter. These enumerator values cannot
be used with scalar parameters:
Member Description
EXTFNAPIV4_DESCRIBE_PARM_TABLE_UNUSED_COL- The list of output table col-
UMNS umns that are not going to be
consumed by the server or the
UDF.
Implementation
typedef enum a_v4_extfn_describe_return {
EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE = 0, // the specified operation has no
meaning either for this attribute or in
length is insufficient.
EXTFNAPIV4_DESCRIBE_INVALID_PARAMETER = -2, // the provided parameter number
is invalid
EXTFNAPIV4_DESCRIBE_INVALID_COLUMN = -3, // the column number is invalid
for this TABLE parameter
EXTFNAPIV4_DESCRIBE_INVALID_STATE = -4, // the describe method call is not
valid in the present state
EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE = -5, // the attribute is known but not
appropriate for this object
EXTFNAPIV4_DESCRIBE_UNKNOWN_ATTRIBUTE = -6, // the identified attribute is
not known to this server version
EXTFNAPIV4_DESCRIBE_NON_TABLE_PARAMETER = -7, // the specified parameter is
not a TABLE parameter (for describe_col_get()
or set())
EXTFNAPIV4_DESCRIBE_INVALID_ATTRIBUTE_VALUE = -8, // the specified attribute
value is illegal
EXTFNAPIV4_DESCRIBE_LAST = -9
} a_v4_extfn_describe_return;
Members Summary
Member Re- Description
turn
Value
EXTFNAPIV4_DESCRIBE_NOT_AVAILABLE 0 The specified operation
has no meaning either for
this attribute or in the cur-
rent context.
Description
The return value of a_v4_extfn_proc_context.describe_xxx_get() and
a_v4_extfn_proc_context.describe_xxx_set() is a signed integer. If the
result is positive, the operation succeeds, and the value is the number of bytes copied. If the
return value is less or equal to zero, the operation does not succeed, and the return value is one
of the a_v4_extfn_describe_return values.
Implementation
typedef enum a_v4_extfn_describe_udf_type {
EXTFNAPIV4_DESCRIBE_UDF_NUM_PARMS,
EXTFNAPIV4_DESCRIBE_UDF_LAST
} a_v4_extfn_describe_udf_type;
Members Summary
Member Description
EXTFNAPIV4_DE- The number of parameters supplied to the UDF.
SCRIBE_UDF_NUM_PARMS
Description
The a_v4_extfn_proc_context.describe_udf_get() method is used by the
UDF to retrieve properties, and the
a_v4_extfn_proc_context.describe_udf_set() method is used by the UDF
to set properties about the UDF as a whole. The a_v4_extfn_describe_udf_type
enumerator selects the logical property the UDF retrieves or sets.
See also
• External Procedure Context (a_v4_extfn_proc_context) on page 292
Implementation
typedef enum a_v4_extfn_state {
EXTFNAPIV4_STATE_INITIAL, // Server initial state,
not used by UDF
EXTFNAPIV4_STATE_ANNOTATION, // Annotating parse
tree with UDF reference
EXTFNAPIV4_STATE_OPTIMIZATION, // Optimizing
EXTFNAPIV4_STATE_PLAN_BUILDING, // Building execution
plan
EXTFNAPIV4_STATE_EXECUTING, // Executing UDF and
fetching results from UDF
EXTFNAPIV4_STATE_LAST
} a_v4_extfn_state;
Members Summary
Member Description
EXTFNAPIV4_STATE_INITIAL Server initial phase. The only UDF method that is
called during this query processing phase is
_start_extfn.
EXTFNAPIV4_STATE_ANNOTATION Annotating parse tree with UDF reference. The
UDF is not invoked during this phase.
Member Description
EXTFNAPIV4_STATE_LAST First illegal value for v4 API. Out-of-band value.
Description
The a_v4_extfn_state enumeration indicates which stage of UDF execution the server
is in. When the server makes a transition from one phase to the next, the server informs the
UDF it is leaving the previous phase by calling the UDF’s _leave_state_extfn
function. The server informs the UDF it is entering the new phase by calling the UDF’s
_enter_state_extfn function.
The query processing phase of a UDF restricts the operations that the UDF can perform. For
example, in the Annotation phase, the UDF can retrieve the data types only for constant
parameters.
See also
• Query Processing States on page 121
• _start_extfn on page 289
• _evaluate_extfn on page 290
• _enter_state_extfn on page 291
• _leave_state_extfn on page 291
• Table Functions (a_v4_extfn_table_func) on page 319
Method Summary
Method Description
_start_extfn Allocates a structure and stores its address in the
_user_data field in the
a_v4_extfn_proc_context.
_finish_extfn Deallocates a structure whose address was stored
in the user_data field in the
a_v4_extfn_proc_context.
Method Description
_evaluate_extfn Required function pointer to be called for each
invocation of the function on a new set of argu-
ment values.
_start_extfn
Use the _start_extfn v4 API method as an optional pointer to an initializer function, for
which the only argument is a pointer to a_v4_extfn_proc_context structure.
Declaration
_start_extfn(
a_v4_extfn_proc_context *
)
Usage
Use the _start_extfn method to allocate a structure and store its address in the
_user_data field in the a_v4_extfn_proc_context. This function pointer must be
set to the null pointer if there is no need for any initialization.
Parameters
Parameter Description
cntxt The procedure context object.
_finish_extfn
Use the _finish_extfn v4 API method as an optional pointer to a shutdown function, for
which the only argument is a pointer to a_v4_extfn_proc_context.
Declaration
_finish_extfn(
a_v4_extfn_proc_context *cntxt,
)
Usage
The _finish_extfn API deallocates a structure for which the address was stored in the
user_data field in the a_v4_extfn_proc_context. This function pointer must be
set to the null pointer if there is no need for any cleanup.
Parameters
Parameter Description
cntxt The procedure context object.
_evaluate_extfn
Use the _evaluate_extfn v4 API method as a required function pointer that is called for
each invocation of the function on a new set of argument values.
Declaration
_evaluate_extfn(
a_v4_extfn_proc_context *cntxt,
void *args_handle
)
Usage
The _evaluate_extfn function must describe to the server how to fetch results by filling
in the a_v4_extfn_table_func portion of the a_v4_extfn_table structure and
use the set_value method on the context with argument zero to send this information to the
server. This function must also inform the server of its output schema by filling in the
a_v4_extfn_value_schema of the a_v4_extfn_table structure before calling
set_value on argument 0. It can access its input argument values via the get_value
callback function. Both constant and nonconstant arguments are available to the UDF at this
time.
Parameters
Parameter Description
cntxt The procedure context object.
_describe_extfn
_describe_extfn is called at the beginning of each state to allow the server to get and set
logical properties. The UDF can do this by using the six describe methods
(describe_parameter_get, describe_parameter_set,
_enter_state_extfn
The UDF can implement the _enter_state_extfn v4 API method as an optional entry
point to be notified whenever the UDF enters a new state.
Declaration
_enter_state_extfn(
a_v4_extfn_proc_context *cntxt,
)
Usage
The UDF can use this notification to allocate structures.
Parameters
Parameter Description
cntxt The procedure context object.
_leave_state_extfn
The _leave_state_extfn v4 API method is an optional entry point the UDF can
implement to receive a notification when the UDF moves out of a query processing state.
Declaration
_leave_state_extfn(
a_v4_extfn_proc_context *cntxt,
)
Usage
The UDF can use this notification to release memory or resources needed for the state.
Parameters
Parameter Description
cntxt The procedure context object.
Implementation
typedef struct a_v4_extfn_proc_context {
.
.
.
} a_v4_extfn_proc_context;
Method Summary
Re- Method Description
turn
Type
short get_value Gets input arguments to the UDF.
short get_value_is_constant Allows the UDF to ask whether a given argument is a con-
stant.
a_sql_ get_is_cancelled Call the get_is_cancelled callback every second or two to see
uint32 if the user has interrupted the current statement.
short set_error Rolls back the current statement and generates an error.
void free Free the memory allocated by alloc() for the specified life-
time.
short set_cannot_be_distrib- Disables distribution at the UDF level even if the library is
uted distributable.
_executionMode a_sql_ui Indicates the debug/trace level requested via the Exter-
nt32 nal_UDF_Execution_Mode option. This is a read-only field.
current_state a_sql_ui The current_state attribute reflects the current execution mode of
nt32 the context. This can be queried from functions such as _de-
scribe_extfn to determine what course of action to take.
Description
In addition to retaining context information from the server and the UDF, the structure
a_v4_extfn_proc_context allows the UDF to call back into the server to perform
certain actions. The UDF can store private data in this structure in the _user_data member.
An instance of this structure gets passed to the functions in the a_v4_extfn_proc method
by the server. User data is not maintained until after the server reaches the Annotation state.
get_value
Use the get_value v4 API method to obtain the values of input arguments sent to the UDF
in a SQL query.
Declaration
short get_value(
void * arg_handle,
a_sql_uint32 arg_num,
an_extfn_value *value
)
Usage
The get_value API is used in an evaluation method to retrieve the value of each input
argument to the UDF. For narrow argument data types (>32K), a call to get_value is
sufficient to retrieve the entire argument value.
The get_value API can be called from any API that has access to the arg_handle
pointer. This includes API functions that take a_v4_table_context as a parameter. The
a_v4_table_context has an args_handle member variable that can be used for this
purpose.
For all fixed-length data types, the data is available in the returned value and no further calls
are necessary to obtain all of the data. The producer can decide what the maximum length is
that is returned entirely in the call to get_value method. All fixed length data types should
be guaranteed to fit in a single contiguous buffer. For variable-length data, the limit is
producer-dependant.
For nonfixed-length data types, and depending on the length of the data, a blob may need to be
created using the get_blob method to get the data. You can use the macro
EXTFN_IS_INCOMPLETE on the value returned by get_value to determine whether a blob
object is required. If EXTFN_IS_INCOMPLETE evaluates to true, a blob is required.
For input arguments that are tables, the type is AN_EXTFN_TABLE. For this type of argument,
you must create a result set using the open_result_set method to read values in from the
table.
If a UDF requires the value of an argument prior to the _evaluate_extfn API being
called, then the UDF should implement the _describe_extfn API. From the
_describe_extfn API, the UDF can obtain the value of constant expressions using the
describe_parameter_get method.
Parameters
Parameter Description
arg_num The index of the argument to get a value for. The argument index starts at 1.
Returns
1 if successful, 0 otherwise.
an_extfn_value Structure
The an_extfn_value structure represents the value of an input argument returned by the
get_value API.
This code shows the declaration of the an_extfn_value structure:
short typedef struct an_extfn_value {
void* data;
a_sql_uint32 piece_len,
an_extfn_value *value {
a_sql_uint32 total_len;
a_sql_uint32 remain_len;
} len;
a_sql_data_type type;
} an_extfn_value;
This table describes what the returned values of an_extfn_value object look like after calling
the get_value method:
Value Re- EXTFN_IS_IN total_len piece_len data
turned by COMPLETE
get_value API
null FALSE 0 0 null
The type field of an_extfn_value contains the data type of the value. For UDFs that have tables
as input arguments, the data type of that argument is DT_EXTFN_TABLE. For v4 Table UDFs,
the remain_len field is not used.
See also
• _evaluate_extfn on page 290
• Table Context (a_v4_extfn_table_context) on page 311
• _describe_extfn on page 290
• *describe_parameter_get on page 242
get_value_is_constant
Use the get_value_is_constant v4 API method to determine whether the specified
input argument value is a constant.
Declaration
short get_value_is_constant(
void * arg_handle,
a_sql_uint32 arg_num,
an_extfn_value *value_is_constant
)
Usage
The UDF can ask whether a given argument is a constant. This is useful for optimizing a UDF,
for example, where work can be performed once during the first call to the
_evaluate_extfn function, rather than for every evaluation call.
Parameters
Parameter Description
arg_num The index value of the input argument being retrieved. Index values are 1..N.
Returns
1 if successful, 0 otherwise.
See also
• _evaluate_extfn on page 290
set_value
Use the set_value v4 API method to describe to the consumer how many columns the
result set has and how data should be read.
Declaration
short set_value(
void * arg_handle,
a_sql_uint32 arg_num,
an_extfn_value *value
)
Usage
This method is used by the UDF in the _evaluate_extfn API. The UDF must call the
set_value method to tell the consumer how many columns are in the result set and what set
of a_v4_extfn_table_func functions the UDF supports.
For the set_value API, the UDF provides an appropriate arg_handle pointer via the
_evaluate_extfnAPI, or from the args_handle member of
a_v4_extfn_table_context structure.
The value argument for the set_value method must be of type DT_EXTFN_TABLE for v4
Table UDFs.
Parameters
Parameter Description
arg_num The index of the argument to set a value for. The only supported argument is 0.
Returns
1 if successful, 0 otherwise.
See also
• _evaluate_extfn on page 290
• Table Functions (a_v4_extfn_table_func) on page 319
• Table Context (a_v4_extfn_table_context) on page 311
get_is_cancelled
Use the get_is_cancelled v4 API method to determine whether the statement has been
cancelled.
Declaration
short get_is_cancelled(
a_v4_extfn_proc_context * cntxt,
Usage
If a UDF entry point is performing work for an extended period of time (many seconds), it
should, if possible, call the get_is_cancelled callback every second or two to see if the
user has interrupted the current statement. If the statement has been interrupted, a nonzero
value is returned and the UDF entry point should then immediately return. Call the
_finish_extfn function to perform necessary cleanup. Do not subsequently call any
other UDF entry points.
Parameters
Parameter Description
Returns
A nonzero value, if the statement is interrupted.
set_error
Use the set_error v4 API method to communicate an error back to the server and
eventually to the user.
Declaration
void set_error(
a_v4_extfn_proc_context * cntxt,
a_sql_uint32 error_number,
const char *error_desc_string
)
Usage
Call the set_error API, if a UDF entry point encounters an error that should send an error
message to the user and shut down the current statement. When called, set_error API rolls
back the current statement and the user sees “Error raised by user-defined
function: <error_desc_string>”. The SQLCODE is the negated form of the
supplied <error_number>.
To avoid collisions with existing error codes, UDFs should generate error numbers between
17000 and 99999. If a number outside this range is provided, the statement is still rolled back,
but the error message is "Invalid error raised by user-defined
function: (<error_number>) <error_desc_string>" with a SQLCODE of
-1577. The maximum length of error_desc_string is 140 characters.
After a call to set_error is made, the UDF entry point should immediately perform a
return; eventually the _finish_extfn function is called to perform necessary cleanup. Do
not subsequently call any other UDF entry points.
Parameters
Parameter Description
See also
• Scalar and Aggregate UDF Callback Functions on page 82
log_message
Use the log_message v4 API method to to send a message to the server's message log.
Declaration
short log_message(
const char *msg,
short msg_length
)
Usage
The log_message method writes a message to the message log. The message string must be
a printable text string no longer than 255 bytes; longer messages may be truncated.
Parameters
Parameter Description
See also
• Controlling Error Checking and Call Tracing on page 27
convert_value
Use the convert_value v4 API method to convert data types.
Declaration
short convert_value(
an_extfn_value *input,
an_extfn_value *output
)
Usage
. The primary use of the convert_value API is the converting between DT_DATE,
DT_TIME, and DT_TIMESTAMP, and DT_TIMESTAMP_STRUCT. An input and output
an_extfn_value is passed to the function.
Input Parameters
Parameter Description
an_extfn_value.data Input data pointer
Output Parameters
Parameter Description
an_extfn_value.data UDF supplied output data point
Returns
1 if successful, 0 otherwise.
See also
• get_value on page 294
get_option
The get_option v4 API method gets the value of a settable option.
Declaration
short get_option(
a_v4_extfn_proc_context * cntxt,
char *option_name,
an_extfn_value *output
)
Parameters
Parameter Description
cntxt The procedure context object
output
• an_extfn_value.data – UDF sup-
plied output data pointer
• an_extfn_value.piece_len –
maximum length of output data
• an_extfn_value.total_len –
server set length of converted output
• an_extfn_value.type – server set
data type of value
Returns
1 if successful, 0 otherwise.
See also
• External Function Prototypes on page 93
• External Procedure Context (a_v4_extfn_proc_context) on page 292
alloc
The alloc v4 API method allocates a block of memory.
Declaration
void*alloc(
a_v4_extfn_proc_context *cntxt,
size_t len
)
Usage
Allocates a block of memory of length at least len. The returned memory is 8-byte aligned.
Tip: Use the alloc() method as your only means of memory allocation, which allows the
server to keep track of how much memory is used by external routines. The server can adapt
other memory users, track leaks, and provide improved diagnostics and monitoring.
Memory tracking is enabled only when external_UDF_execution_mode is set to a value of 1
or 2 (validation mode or tracing mode).
Parameters
Parameter Description
cntxt The procedure context object
See also
• free on page 302
• Enabling Memory Tracking on page 135
free
The free v4 API method frees an allocated block of memory.
Declaration
void free(
a_v4_extfn_proc_context *cntxt,
void *mem
)
Usage
Frees the memory allocated by alloc() for the specified lifetime.
Memory tracking is enabled only when external_UDF_execution_mode is set to a value of 1
or 2 (validation mode or tracing mode).
Parameters
Parameter Description
cntxt The procedure context object
See also
• alloc on page 301
• Enabling Memory Tracking on page 135
open_result_set
The open_result_set v4 API method opens a result set for a table value.
Declaration
short open_result_set(
a_v4_extfn_proc_context *cntxt,
a_v4_extfn_table *table,
a_v4_extfn_table_context **result_set
)
Usage
open_result_set opens a result set for a table value. A UDF can open a result set to read
rows from an input parameter of type DT_EXTFN_TABLE. The server (or another UDF) can
open a result set to read rows from the UDF.
Parameters
Parameter Description
cntxt The procedure context object
Returns
1 if successful, 0 otherwise.
See the fetch_block and fetch_into v4 API method descriptions for examples of the
use of open_result_set.
See also
• External Procedure Context (a_v4_extfn_proc_context) on page 292
• fetch_into on page 313
• fetch_block on page 316
close_result_set
The close_result_set v4 API method closes an open result set.
Declaration
short close_result_set(
a_v4_extfn_proc_context *cntxt,
a_v4_extfn_table_context *result_set
)
Usage
You can only use close_result_set once per result set.
Parameters
Parameter Description
cntxt The procedure context object
Returns
1 if successful, 0 otherwise.
get_blob
Use the get_blob v4 API method to retrieve an input blob parameter.
Declaration
short get_blob(
void *arg_handle,
a_sql_uint32 arg_num,
a_v4_extfn_blob **blob
)
Usage
Use get_blob to retrieve a blob input parameter after calling get_value(). Use the
macro EXTFN_IS_INCOMPLETE to determine if a blob object is required to read the data
for the value returned from get_value(), if piece_len < total_len. The blob object is
returned as an output parameter and is owned by the caller.
get_blob obtains a blob handle that can be used to read the contents of the blob. Call this
method only on columns that contain blob objects.
Parameters
Parameter Description
Returns
1 if successful, 0 otherwise.
See also
• External Procedure Context (a_v4_extfn_proc_context) on page 292
• get_value on page 294
set_cannot_be_distributed
The set_cannot_be_distributed v4 API method disables distributions at the UDF
level, even if the distribution criteria are met at the library level.
Declaration
void set_cannot_be_distributed( a_v4_extfn_proc_context *cntxt)
Usage
In the default behavior, if the library is distributable, then the UDF is distributable. Use
set_cannot_be_distributed in the UDF to push the decision to disable distribution
to the server.
Implementation
typedef struct an_extfn_license_info {
short version;
} an_extfn_license_info;
info Value the UDF sets for additional library information such as library version
and build numbers.
key (Design partners only) An SAP-supplied license key. The key is a 26-character
array.
Implementation
typedef struct a_v4_extfn_estimate {
double value;
double confidence;
} a_v4_extfn_estimate;
Implementation
typedef struct a_v4_extfn_orderby_list {
a_sql_uint32 number_of_elements;
a_v4_extfn_order_el order_elements[1]; // there are
number_of_elements entries
} a_v4_extfn_orderby_list;
Description
There are number_of_elements entries, each with a flag indicating whether the element is
ascending or descending, and a column index indicating the appropriate column in the
associated table.
See also
• Column Order (a_v4_extfn_order_el) on page 206
Implementation
typedef enum a_v4_extfn_partitionby_col_num {
EXTFNAPIV4_PARTITION_BY_COLUMN_NONE = -1, // NO PARTITION
BY
EXTFNAPIV4_PARTITION_BY_COLUMN_ANY = 0, // PARTITION BY
ANY
// + INTEGER representing a specific
column ordinal
} a_v4_extfn_partitionby_col_num;
Members Summary
Member of a_v4_extfn_partition- Val- Description
by_col_num Enumerated Type ue
EXTFNAPIV4_PARTITION_BY_COL- -1 NO PARTITION BY
UMN_NONE
Column Ordinal Number N>0 Ordinal for the table column number
to partition on
Description
This structure allows the UDF to programmatically describe the partitioning and the column
to partition on.
Use this enumeration when populating the a_v4_extfn_column_list
number_of_columns field. When describing partition by support to the server, the UDF
sets the number_of_columns to one of the enumerated values, or to a positive integer
representing the number of column ordinals listed. For example, to describe to the server that
no partitioning is supported, create the structure as:
a_v4_extfn_column_list nopby = {
EXTFNAPIV4_PARTITION_BY_COLUMN_NONE,
0
};
Row (a_v4_extfn_row)
Use the a_v4_extfn_row structure to represent the data in a single row.
Implementation
/* a_v4_extfn_row - */
typedef struct a_v4_extfn_row {
a_sql_uint32 *row_status;
a_v4_extfn_column_data *column_data;
} a_v4_extfn_row;
row_status a_sql_uint32 * The status of the row. Set to 1 for existing rows and 0
otherwise.
Description
The row structure contains information for a specific row of columns. This structure defines
the status of an individual row and includes a pointer to the individual columns within the row.
The row status is a flag that indicates the existence of a row. The row status flag can be altered
by nested fetch calls without requiring manipulation of the row block structure.
The row_status flag set as 1 indicates that the row is available and can be included in the result
set. The row_status set as 0 means the row should be ignored. This is useful when the TPF is
acting as a filter because TPF may pass through rows of an input table to the result set, but it
may also want to skip certain rows, which it can do by setting a status of 0 for those rows.
See also
• Column Data (a_v4_extfn_column_data) on page 204
Implementation
/* a_v4_extfn_row_block - */
typedef struct a_v4_extfn_row_block {
a_sql_uint32 max_rows;
a_sql_uint32 num_rows;
a_v4_extfn_row *row_data;
} a_v4_extfn_row_block;
max_rows a_sql_uint32 The maximum number of rows this row block can handle
num_rows a_sql_uint32 Must be less than or equal to the maximum of rows the row
block contains
Description
The row block structure is utilized by the fetch_into and fetch_block methods to
allow the production and consumption of data. The allocator sets the maximum number of
rows. The producer icorrectly sets the number of rows. The data consumer should not attempt
to read more than number of rows produced.
The owner of the row_block structure determines the value of max_rows data member. For
example, when a table UDF is implementing fetch_into, the value of max_rows is
determined by the server as the number of rows that can fit into 128K of memory. However,
when a table UDF is implementing fetch_block, the table UDF itself determines the value
of max_rows.
Table (a_v4_extfn_table)
Use the a_v4_extfn_table structure to represent how data is stored in a table and how
the consumer fetches that data.
Implementation
typedef struct a_v4_extfn_table {
a_v4_extfn_table_func *func;
a_sql_uint32 number_of_columns;
} a_v4_extfn_table;
Implementation
typedef struct a_v4_extfn_table_context {
// size_t struct_size;
The row_block parameter is in/out. The first call should point to a NULL row
block.
The fetch_block() call sets row_block to a block that can be consumed, and this
block
should be passed on the next fetch_block() call.
*/
short (UDF_CALLBACK *fetch_block)(a_v4_extfn_table_context *cntxt,
a_v4_extfn_row_block **row_block);
/* get_blob() - If the specified column has a blob object, return it. The blob
is returned as an out parameter and is owned by the caller. This method should
only be called on a column that contains a blob. The helper macro
EXTFN_COL_IS_BLOB can
be used to determine whether a column contains a blob.
*/
short (UDF_CALLBACK *get_blob)(a_v4_extfn_table_context *cntxt,
a_v4_extfn_column_data *col,
a_v4_extfn_blob **blob);
/* The following fields are reserved for future use and must be initialized to NULL.
*/
void *reserved1_must_be_null;
void *reserved2_must_be_null;
void *reserved3_must_be_null;
void *reserved4_must_be_null;
void *reserved5_must_be_null;
a_v4_extfn_proc_context *proc_context;
void *args_handle; // use in
a_v4_extfn_proc_context::get_value() etc.
a_v4_extfn_table *table;
void *user_data;
void *server_internal_use;
/* The following fields are reserved for future use and must be initialized to NULL.
*/
void *reserved6_must_be_null;
void *reserved7_must_be_null;
void *reserved8_must_be_null;
void *reserved9_must_be_null;
void *reserved10_must_be_null;
} a_v4_extfn_table_context;
Method Summary
Data Method Description
Type
short fetch_into Fetch into a specified row_block
short rewind Restarts the result set at the beginning of the table
short get_blob Return a blob object, if the specified column has a blob object
table a_v4_extfn_table * Points to the open result set table. This is populated after
a_v4_extfn_proc_context open_re-
sult_set has been called.
user_data void * This data pointer can be filled in by any usage with whatever
context data the external routine requires.
Description
The a_v4_extfn_table_context structure acts as a middle layer between the
producer and the consumer to help manage the data, when the consumer and producer require
separate formats.
A UDF can read rows from an input TABLE parameter using
a_v4_extfn_table_context. The server or another UDF can read rows from the result
table of a UDF using a_v4_extfn_table_context.
The server implements the methods of a_v4_extfn_table_context, which gives the
server an opportunity to resolve impedance mismatches.
See also
• fetch_into on page 313
• fetch_block on page 316
• rewind on page 318
fetch_into
The fetch_into v4 API method fetches data into a specified row block.
Declaration
short fetch_into(
a_v4_extfn_table_context *cntxt,
a_v4_extfn_row_block *)
Usage
The fetch_into method is useful when the producer does not know how data should be
arranged in memory. This method is used as an entry point when the consumer has a transfer
area with a specific format. The fetch_into() function writes the fetched rows into the
provided row block. This method is part of the a_v4_extfn_table_context structure.
Use fetch_into when the consumer owns the memory for the data transfer area and
requests that the producer use this area. You use the fetch_into method when the
consumer cares about how the data transfer area is set up and it is up to the producer to perform
the necessary data copying into this area.
Parameters
Parameter Description
cntxt The table context object obtained from the
open_result_set API
row_block The row block object to fetch into
Returns
1 if successful, 0 otherwise.
If the UDF returns 1, the consumer knows that there are more rows left and the fetch_into
method should be called again. However, a UDF returning a value of 0 indicates that there are
no more rows and a call to the fetch_into method is unnecessary.
Consider the following procedure definition, which is an example of a TPF function that
consumes an input parameter table and produces it as a result table. Both are instances of SQL
values that are obtained and returned through the get_value and set_value v4 API
methods, respectively.
CREATE PROCEDURE FETCH_EX( IN a INT, INT b TABLE( c1 INT ) )
RESULT SET ( rc INT )
The example shows that prior to fetching/consuming from an input table, a table context must
be established via the open_result_set API on the a_v4_extfn_proc structure. The
open_result_set requires a table object, which can be obtained through the
get_value API.
an_extfn_value arg;
ctx->get_value( args_handle, 3, &arg );
After the table context is created, the rs structure executes the fetch_into API and fetches
the rows.
a_v4_extfn_row_block *rb = // get a row block to hold a series of
INT values.
rs->fetch_into( rs, &rb ) // fetch the rows.
Prior to producing rows to a result table, a table object must be created and returned to the
caller via the set_value API on the a_v4_extfn_proc_context structure.
This example shows that a table UDF must create an instance of the a_v4_extfn_table
structure. Each invocation of the table UDF should return a separate instance of the
a_v4_extfn_table structure. The table contains the state fields to keep track of the
current row and the number of rows to generate. State for a table can be stored as a field of the
instance.
typedef struct rg_table : a_v4_extfn_table {
a_sql_uint32 rows_to_generate;
a_sql_uint32 current_row;
} my_table;
In the following example, each time a row is produced, current_row is incremented until the
number of rows to be generated is reached, when fetch_into returns false to indicate end-
of-file. The consumer executes the fetch_into API implemented by the table UDF. As
part of the call to the fetch_into method, the consumer provides the table context, as well
as the row block to fetch into.
rs->fetch_into( rs, &rb )
return 0;
}
See also
• The fetch_into Method on page 130
• Table Context (a_v4_extfn_table_context) on page 311
• Row Block (a_v4_extfn_row_block) on page 309
• External Procedure Context (a_v4_extfn_proc_context) on page 292
• get_value on page 294
• set_value on page 297
• Table (a_v4_extfn_table) on page 310
fetch_block
The fetch_block v4 API method fetches a block of rows.
Declaration
short fetch_block(
a_v4_extfn_table_context *cntxt,
a_v4_extfn_row_block **row_block)
Usage
The fetch_block method is used as an entry point when the consumer does not need the
data in a particular format. fetch_block requests that the producer create a data transfer
area and provide a pointer to that area. The consumer owns the memory and takes
responsibility for copying data from this area.
The fetch_block is more efficient if the consumer does not require a specific layout. The
fetch_block call sets a fetch_block to a block that can be consumed, and this block
should be passed on the next fetch_block call. This method is part of the
a_v4_extfn_table_context structure.
Parameters
Parameter Description
cntxt The table context object.
When fetch_block is called and row_block points to NULL, the UDF must allocate a
a_v4_extfn_row_block structure.
Returns
1 if successful, 0 otherwise.
If the UDF returns 1, the consumer knows that there are more rows left and calls the
fetch_block method again. However, a UDF returning a value of 0 indicates that there are
no more rows and a call to the fetch_block method is unnecessary.
Consider the following procedure definition, which is an example of a TPF function that
consumes an input parameter table and produces it as a result table. Both are instances of SQL
values that are obtained and returned through the get_value and set_value v4 API
methods, respectively.
CREATE PROCEDURE FETCH_EX( IN a INT, INT b TABLE( c1 INT ) )
RESULT SET ( rc INT )
The example shows that prior to fetching/consuming from an input table, a table context must
be established via the open_result_set API on the a_v4_extfn_proc structure. The
open_result_set requires a table object, which can be obtained through the
get_value API.
an_extfn_value arg;
ctx->get_value( args_handle, 3, &arg );
After the table context is created, the rs structure executes the fetch_block API and
fetches the rows.
a_v4_extfn_row_block *rb = // get a row block to hold a series of
INT values.
rs->fetch_block( rs, &rb ) // fetch the rows.
Prior to producing rows to a result table, a table object must be created and returned to the
caller via the set_value API on the a_v4_extfn_proc_context structure.
This example shows that a table UDF must create an instance of the a_v4_extfn_table
structure. Each invocation of the table UDF should return a separate instance of the
a_v4_extfn_table structure. The table contains the state fields to keep track of the
current row and the number of rows to generate. State for a table can be stored as a field of the
instance.
typedef struct rg_table : a_v4_extfn_table {
a_sql_uint32 rows_to_generate;
a_sql_uint32 current_row;
} my_table;
See also
• The fetch_block Method on page 130
• Table Context (a_v4_extfn_table_context) on page 311
• Row Block (a_v4_extfn_row_block) on page 309
• External Procedure Context (a_v4_extfn_proc_context) on page 292
rewind
Use the rewind v4 API method to restart a result set at the beginning of the table.
Declaration
short rewind(
a_v4_extfn_table_context *cntxt,
)
Usage
Call the rewind method on an open result set to rewind the table to the beginning. If the UDF
intends to rewind an input table, it must inform the producer during the state
EXTFNAPIV4_STATE_OPTIMIZATION using the
EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND parameter.
rewind() is an optional entry point. If NULL, rewind is not supported. Otherwise, the
rewind() entry point restarts the result set at the beginning of the table.
Parameters
Parameter Description
cntxt The table context object
Returns
1 if successful, 0 otherwise.
See also
• Query Optimization State on page 124
• Execution State on page 128
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND Attribute (Set) on
page 273
get_blob
Use the get_blob v4 API method to return a blob object from a specified column.
Declaration
short get_blob(
a_v4_extfn_table_context *cntxt,
a_v4_extfn_column_data *col,
a_v4_extfn_blob **blob
)
Usage
The blob is returned as an output parameter and is owned by the caller. Call this method only
on a column that contains a blob.
Use the helper macro EXTFN_COL_IS_BLOB to determine whether a column contains a
blob. This is the declaration of EXTFN_COL_IS_BLOB in the header file
extfnapiv4.h:
#define EXTFN_COL_IS_BLOB(c, n) (c[n].blob_handle != NULL)
Parameters
Parameter Description
cntxt The table context object
col The column data pointer for which to get the blob
Returns
1 if successful, 0 otherwise.
See also
• Table Context (a_v4_extfn_table_context) on page 311
Implementation
typedef struct a_v4_extfn_table_func {
// size_t struct_size;
/* Open a result set. The UDF can allocate any resources needed
for the result set.
*/
short (UDF_CALLBACK *_open_extfn)(a_v4_extfn_table_context *);
/* Fetch rows into a provided row block. The UDF should implement
this method if it does
not have a preferred layout for its transfer area.
*/
*row_block);
**row_block);
/* The following fields are reserved for future use and must be
initialized to NULL. */
void *_reserved1_must_be_null;
void *_reserved2_must_be_null;
} a_v4_extfn_table_func;
Method Summary
Method Data Type Description
_open_extfn void Called by the server to initiate row fetching by opening
a result set. The UDF can allocate any resources nee-
ded for the result set.
_fetch_in- short Fetch rows into a provided row block. The UDF im-
to_extfn plements this method, if it does not have a preferred
layout for its transfer area.
Description
The a_v4_extfn_table_func structure defines the methods used to fetch results from a
table.
See also
• Table (a_v4_extfn_table) on page 310
• Table Context (a_v4_extfn_table_context) on page 311
• _open_extfn on page 321
• _fetch_into_extfn on page 322
• _fetch_block_extfn on page 322
• _rewind_extfn on page 323
• _close_extfn on page 324
_open_extfn
The server calls the_open_extfn v4 API method to initiate fetching of rows.
Declaration
void _open_extfn(
a_v4_extfn_table_context *cntxt,
)
Usage
The UDF uses this method to open a result set and allocate any resources (for example,
streams) needed for sending results to the server.
Parameters
Parameter Description
cntxt The procedure context object
See also
• Table Context (a_v4_extfn_table_context) on page 311
_fetch_into_extfn
The _fetch_into_extfn v4 API method fetches rows into a provided row block.
Declaration
short _fetch_into_extfn(
a_v4_extfn_table_context *cntxt,
a_v4_extfn_row_block *row_block
)
Usage
The UDF should implement this method, if it does not have a preferred layout for its transfer
area.
Parameters
Parameter Description
cntxt The procedure context object
Returns
1 if successful, 0 otherwise.
See also
• Table Context (a_v4_extfn_table_context) on page 311
• Row Block (a_v4_extfn_row_block) on page 309
_fetch_block_extfn
The _fetch_block_extfn v4 API method fetches a block that is allocated and
configured by the UDF.
Declaration
short _fetch_block_extfn(
a_v4_extfn_table_context *cntxt,
a_v4_extfn_row_block **
)
Usage
The UDF should implement this method, if it has a preferred layout for its transfer area.
Parameters
Parameter Description
cntxt The procedure context object
Returns
1 if successful, 0 otherwise.
See also
• Table Context (a_v4_extfn_table_context) on page 311
• Row Block (a_v4_extfn_row_block) on page 309
_rewind_extfn
The _rewind_extfn v4 API method restarts a result set at the beginning of the table.
Declaration
void _rewind_extfn(
a_v4_extfn_table_context *cntxt,
)
Usage
This function is an optional entry point. The UDF implements the _rewind_extfn method
when the result table is rewound to the beginning. The UDF should consider implementing
this method only if it can provide the rewind functionality in an efficient and cost-effective
manner.
If a UDF chooses to implement the _rewind_extfn method, it should tell the consumer
during the state EXTFNAPIV4_STATE_OPTIMIZATION by setting the
EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND parameter for argument 0.
The UDF may decide not to provide the rewind functionality, in which case the server
compensates and provides the functionality.
Note: The server can choose not to call the _rewind_extfn method to perform the rewind.
Parameters
Parameter Description
cntxt The procedure context object
Returns
No return value.
See also
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND Attribute (Get) on
page 258
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_REQUEST_REWIND Attribute (Set) on
page 273
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND Attribute (Set) on page
275
• EXTFNAPIV4_DESCRIBE_PARM_TABLE_HAS_REWIND Attribute (Get) on page
259
• Query Processing States on page 121
• Execution State (a_v4_extfn_state) on page 287
• Table Context (a_v4_extfn_table_context) on page 311
_close_extfn
The server calls the _close_extfn v4 API method to terminate fetching of rows.
Declaration
void _close_extfn(
a_v4_extfn_table_context *cntxt,
)
Usage
The UDF uses this method when fetching is complete to close a result set and release any
resources allocated for the result set.
Parameters
Parameter Description
cntxt The procedure context object
See also
• Table Context (a_v4_extfn_table_context) on page 311
Get Set
EXTFNAPIV4_DESCRIBE_ BUF- EXTFNAPIV4_DESCRIBE_ BUF-
FER_SIZE_MISMATCH – get error returned FER_SIZE_MISMATCH – set error returned
if the cntxt or describe_buffer are NULL, or if if the cntxt or describe_buffer are NULL, or if
the describe_buffer_length is 0. the describe_buffer_length is 0.
EXTFNAPIV4_DESCRIBE_INVA- EXTFNAPIV4_DESCRIBE_INVA-
LID_STATE – get error returned if the cntxt LID_STATE – set error returned if the cntxt
parameter is not a valid context. parameter is not a valid context.
EXTFNAPIV4_DESCRIBE_INVA- EXTFNAPIV4_DESCRIBE_INVA-
LID_PARAMETER – get error returned if the LID_PARAMETER – set error returned if the
provided parameter number is outside legal range provided parameter number is outside legal range
for the procedure: < 0 or > the number of param- for the procedure: < 0 or > the number of param-
eters for the procedure. eters for the procedure.
EXTFNAPIV4_DESCRIBE_NON_TA- EXTFNAPIV4_DESCRIBE_NON_TA-
BLE_PARAMETER – get error returned if BLE_PARAMETER – set error returned if
arg_num is not a TABLE parameter. arg_num is not a TABLE parameter.
EXTFNAPIV4_DESCRIBE_INVA- EXTFNAPIV4_DESCRIBE_INVA-
LID_COLUMN – get error returned if the col- LID_COLUMN – set error returned if the col-
umn number is not valid for the TABLE param- umn number is not valid for the TABLE param-
eter. eter.
EXTFNAPIV4_DESCRIBE_UN- EXTFNAPIV4_DESCRIBE_UN-
KNOWN_ATTRIBUTE – get error returned if KNOWN_ATTRIBUTE – set error returned if
the value of describe_type is not one of the valid the value of describe_type is not one of the valid
describe types from a_v4_extfn_de- describe types from a_v4_extfn_de-
scribe_parm_type. scribe_parm_type.
Get Set
EXTFNAPIV4_DESCRIBE_INVA- EXTFNAPIV4_DESCRIBE_INVA-
LID_PARAMETER – get error returned if any LID_PARAMETER – set error returned if any
of the cntxt or describe_buffer arguments are of the cntxt or describe_buffer arguments are
NULL or if describe_buffer_length is 0. NULL or if describe_buffer_length is 0.
EXTFNAPIV4_DESCRIBE_INVA- EXTFNAPIV4_DESCRIBE_INVA-
LID_PARAMETER – get error returned if the LID_PARAMETER – set error returned if the
cntxt parameter is an invalid context. cntxt parameter is an invalid context.
Get Set
EXTFNAPIV4_DESCRIBE_INVA- EXTFNAPIV4_DESCRIBE_INVA-
LID_PARAMETER – get error returned if the LID_PARAMETER – set error returned if the
cntxt or describe_buffer is NULL, or if de- cntxt or describe_buffer is NULL, or if de-
scribe_buffer_length is 0. scribe_buffer_length is 0.
EXTFNAPIV4_DESCRIBE_INVA- EXTFNAPIV4_DESCRIBE_INVA-
LID_PARAMETER – get error returned if the LID_PARAMETER – set error returned if the
cntxt parameter is invalid. cntxt parameter is invalid.
EXTFNAPIV4_DESCRIBE_INVA- EXTFNAPIV4_DESCRIBE_INVA-
LID_PARAMETER – get error returned if the LID_PARAMETER – set error returned if the
provided parameter number is outside the legal provided parameter number is outside the legal
range for the procedure; that is, if the parameter range for the procedure; that is, if the parameter
number is < 0 or > the number of parameters for number is < 0 or > the number of parameters for
the procedure. the procedure.
Get Set
EXTFNAPIV4_DESCRIBE_ UN- EXTFNAPIV4_DESCRIBE_ UN-
KNOWN_ATTRIBUTE – get error returned if KNOWN_ATTRIBUTE – set error returned if
the value of describe_type is an invalid the value of describe_type is an invalid
a_v4_extfn_describe_parm_type a_v4_extfn_describe_parm_type
describe type. describe type.
EXTFNAPIV4_DESCRIBE_BUF- EXTFNAPIV4_DESCRIBE_BUF-
FER_SIZE_MISMATCH – get error returned FER_SIZE_MISMATCH – set error returned
if there is a discrepancy between the requested if there is a discrepancy between the size of the
attribute size and the supplied de- requested attribute and the supplied de-
scribe_buffer_length. For fixed-size scribe_buffer_length. For fixed-size attributes,
attributes, such as an a_sql_byte data type, such as an a_sql_byte data type, the sizes
the sizes must match. For variable-length attrib- must match.
ute data types, such as char[], the supplied
buffer needs to be at least large enough to hold the
value of the requested attribute.
See also
• Query Processing States on page 121
where:
• tabudf() is a table UDF, and
• the UDF my_sum1() does not exist on the server,
this error is returned:
Could not execute statement.
External procedures or functions are not allowed across server types.
SQLCODE=-1579, ODBC 3 State="HY000"
Line 1, column 1
System Tables
The system table SYSEXTERNENV stores the information needed to identify and launch each
of the external environments.
The system table SYSEXTERNENVOBJECT stores non-Java external objects.
SQL Statements
The following SQL syntax allows you to set or modify the location of external environments in
the SYSEXTERNENV table.
ALTER EXTERNAL ENVIRONMENT environment-name
[ LOCATION location-string ]
Once an external environment is set up to be used on the database server, you can then install
objects into the database and create stored procedures and functions that make use of these
objects within the external environment. Installing, creating, and using these objects, stored
procedures, and stored functions is similar to installing Java classes and creating and using
Java stored procedures and functions.
To add a comment for an external environment, you can execute:
COMMENT ON EXTERNAL ENVIRONMENT environment-name
IS comment-string
To install a Perl or PHP external object (for example, a Perl script) from a file or an expression
into the database, execute an INSTALL EXTERNAL OBJECT statement similar to:
INSTALL EXTERNAL OBJECT object-name-string
[ update-mode ]
FROM { FILE file-path | VALUE expression }
ENVIRONMENT environment-name
To add a comment for an installed Perl or PHP external object, you can execute:
COMMENT ON EXTERNAL [ENVIRONMENT] OBJECT object-name-string
IS comment-string
To remove an installed Perl or PHP external object from the database, use a REMOVE
EXTERNAL OBJECT statement:
REMOVE EXTERNAL OBJECT object-name-string
Once external objects are installed in the database, you can use them in external stored
procedure and function definitions (similar to the current mechanism for creating Java stored
procedures and functions).
CREATE PROCEDURE procedure-name(...)
EXTERNAL NAME '...'
LANGUAGE environment-name
Once these stored procedures and functions are created, you can use them like any other stored
procedure or function in the database. The database server, when encountering an external
environment stored procedure or function, automatically launches the external environment
(if it has not already been started), and sends the necessary information to get the external
environment to fetch the external object from the database and execute it. Any result sets or
return values resulting from the execution are returned as needed.
To start or stop an external environment on demand, use the START EXTERNAL
ENVIRONMENT and STOP EXTERNAL ENVIRONMENT statements:
START EXTERNAL ENVIRONMENT environment-name
STOP EXTERNAL ENVIRONMENT environment-name
Prerequisites
There are no licensing prerequisites. The external runtime environments do not require the
IQ_IDA license. The external runtime environments do not require the a_v3_extfn or
a_v4_extfn APIs.
Task
See also
• The ESQL and ODBC External Environments on page 331
• The Java External Environment on page 341
• PERL External Environment on page 369
• PHP External Environment on page 373
• CREATE PROCEDURE Statement (Java UDF) on page 361
• CREATE FUNCTION Statement (Java UDF) on page 363
See also
• Java External Environment Restrictions on page 347
Unlike the Perl, PHP, and Java external environments, you do not install any source code or
compiled objects in the database. As a result, you do not need to execute any INSTALL
statements before using the ESQL and ODBC external environments.
Here is an example of a function written in C++ that can be run within the database server or in
an external environment.
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extfnapi.h"
j = 1000;
k = 0;
for( i = 1; i <= 4; i++ )
{
result = api->get_value( arg_handle, i, &arg );
if( result == 0 || arg.data == NULL ) break;
if( arg.type & DT_TYPES != DT_INT ) break;
intptr = (int *) arg.data;
k += *intptr * j;
j = j / 10;
}
retval.type = DT_INT;
retval.data = (void*)&k;
retval.piece_len = retval.len.total_len =
(a_sql_uint32) sizeof( int );
api->set_value( arg_handle, 0, &retval, 0 );
return;
}
When compiled into a dynamic link library or shared object, this function can be called from
an external environment. An executable image called dbexternc12 is started by the database
server and this executable image loads the dynamic link library or shared object for you.
Note that 32-bit or 64-bit versions of the database server can be used and either version can
start 32-bit or 64-bit versions of dbexternc12. This is one of the advantages of using the
external environment. Note that once dbexternc12 is started by the database server, it does not
terminate until the connection has been terminated or a STOP EXTERNAL
ENVIRONMENT statement (with the correct environment name) is executed. Each
connection that does an external environment call will get its own copy of dbexternc12.
To call the compiled native function, SimpleCFunction, a wrapper is defined as follows:
CREATE FUNCTION SimpleCDemo(
IN arg1 INT,
IN arg2 INT,
IN arg3 INT,
IN arg4 INT )
RETURNS INT
EXTERNAL NAME 'SimpleCFunction@c:\\c\\extdemo.dll'
LANGUAGE C_ODBC32;
This is almost identical to the way a compiled native function is described when it is to be
loaded into the database server's address space. The one difference is the use of the
LANGUAGE C_ODBC32 clause. This clause indicates that SimpleCDemo is a function
running in an external environment and that it is using 32-bit ODBC calls. The language
specification of C_ESQL32, C_ESQL64, C_ODBC32, or C_ODBC64 tells the database
server whether the external C function issues 32-bit or 64-bit ODBC, ESQL, or
a_v4_extfn API calls when making server-side requests.
When the native function uses none of the ODBC, ESQL, or SQL Anywhere C API calls to
make server-side requests, then either C_ODBC32 or C_ESQL32 can be used for 32-bit
applications and either C_ODBC64 or C_ESQL64 can be used for 64-bit applications. This is
the case in the external C function shown above. It does not use any of these APIs.
To execute the sample compiled native function, execute the following statement.
SELECT SimpleCDemo(1,2,3,4);
To use server-side ODBC, the C/C++ code must use the default database connection. To get a
handle to the database connection, call get_value with an
EXTFN_CONNECTION_HANDLE_ARG_NUM argument. The argument tells the
database server to return the current external environment connection rather than opening a
new one.
#include <windows.h>
#include <stdio.h>
#include "odbc.h"
#include "extfnapi.h"
LPVOID lpReserved
)
{
return TRUE;
}
ret = -1;
// set up the return value struct
retval.type = DT_INT;
retval.data = (void*) &ret;
retval.piece_len = retval.len.total_len =
(a_sql_uint32) sizeof( int );
If the above ODBC code is stored in the file extodbc.cpp, it can be built for Windows using the
following commands.
cl extodbc.cpp /LD /Ic:\sa12\sdk\include odbc32.lib
The following example creates a table, defines the stored procedure wrapper to call the
compiled native function, and then calls the native function to populate the table.
SELECT ServerSideODBC();
Similarly, to use server-side ESQL, the C/C++ code must use the default database connection.
To get a handle to the database connection, call get_value with an
EXTFN_CONNECTION_HANDLE_ARG_NUM argument. The argument tells the
database server to return the current external environment connection rather than opening a
new one.
#include <windows.h>
#include <stdio.h>
#include "sqlca.h"
#include "sqlda.h"
#include "extfnapi.h"
If the above embedded SQL statements are stored in the file extesql.sqc, it can be built for
Windows using the following commands.
sqlpp extesql.sqc extesql.cpp
cl extesql.cpp /LD /Ic:\sa12\sdk\include c:\sa12\sdk\lib
\x86\dblibtm.lib
The following example creates a table, defines the stored procedure wrapper to call the
compiled native function, and then calls the native function to populate the table.
CREATE TABLE esqlTab(c1 int, c2 char(128));
SELECT ServerSideESQL();
As in the previous examples, to use server-side SAP Sybase IQ C API calls, the C/C++ code
must use the default database connection. To get a handle to the database connection, call
get_value with an EXTFN_CONNECTION_HANDLE_ARG_NUM argument. The
argument tells the database server to return the current external environment connection rather
than opening a new one. The following example shows the framework for obtaining the
connection handle, initializing the C API environment, and transforming the connection
handle into a connection object (a_sqlany_connection) that can be used with the SAP Sybase
IQ C API.
include <windows.h>
#include "sacapidll.h"
#include "extfnapi.h"
SQLAnywhereInterface capi;
a_sqlany_connection * sqlany_conn;
unsigned int max_api_ver;
capi.sqlany_fini();
sqlany_finalize_interface( &capi );
return;
}
If the above C code is stored in the file extcapi.c, it can be built for Windows using the
following commands.
cl /LD /Tp extcapi.c /Tp c:\sa12\SDK\C\sacapidll.c
/Ic:\sa12\SDK\Include c:\sa12\SDK\Lib\X86\dbcapi.lib
The following example defines the stored procedure wrapper to call the compiled native
function, and then calls the native function.
CREATE FUNCTION ServerSideC()
RETURNS INT
EXTERNAL NAME 'ServerSideFunction@extcapi.dll'
LANGUAGE C_ESQL32;
SELECT ServerSideC();
The LANGUAGE attribute in the above example specifies C_ESQL32. For 64-bit
applications, you would use C_ESQL64. You must use the embedded SQL language attribute
since the SAP Sybase IQ C API is built on the same layer (library) as ESQL.
As mentioned earlier, each connection that does an external environment call will start its own
copy of dbexternc12. This executable application is loaded automatically by the server the
first time an external environment call is made. However, you can use the START
EXTERNAL ENVIRONMENT statement to preload dbexternc12. This is useful if you want
to avoid the slight delay that is incurred when an external environment call is executed for the
first time. Here is an example of the statement.
START EXTERNAL ENVIRONMENT C_ESQL32
Another case where preloading dbexternc12 is useful is when you want to debug your external
function. You can use the debugger to attach to the running dbexternc12 process and set
breakpoints in your external function.
The STOP EXTERNAL ENVIRONMENT statement is useful when updating a dynamic link
library or shared object. It will terminate the native library loader, dbexternc12, for the current
connection thereby releasing access to the dynamic link library or shared object. If multiple
connections are using the same dynamic link library or shared object then each of their copies
of dbexternc12 must be terminated. The appropriate external environment name must be
specified in the STOP EXTERNAL ENVIRONMENT statement. Here is an example of the
statement.
STOP EXTERNAL ENVIRONMENT C_ESQL32
To return a result set from an external function, the compiled native function must use the
native function call interface.
The following code fragment shows how to set up a result set information structure. It contains
a column count, a pointer to an array of column information structures, and a pointer to an
array of column data value structures. The example also uses the SAP Sybase IQ C API.
an_extfn_result_set_info rs_info;
an_extfn_result_set_column_info *col_info =
(an_extfn_result_set_column_info *)
malloc( columns * sizeof(an_extfn_result_set_column_info) );
an_extfn_result_set_column_data *col_data =
(an_extfn_result_set_column_data *)
malloc( columns * sizeof(an_extfn_result_set_column_data) );
rs_info.number_of_columns = columns;
rs_info.column_infos = col_info;
rs_info.column_data_values = col_data;
The following code fragment shows how to describe the result set. It uses the SAP Sybase IQ C
API to obtain column information for a SQL query that was executed previously by the C API.
The information that is obtained from the SAP Sybase IQ C API for each column is
transformed into a column name, type, width, index, and null value indicator that will be used
to describe the result set.
a_sqlany_column_info info;
for( int i = 0; i < columns; i++ )
{
if( sqlany_get_column_info( sqlany_stmt, i, &info ) )
{
// set up a column description
col_info[i].column_name = info.name;
col_info[i].column_type = info.native_type;
switch( info.native_type )
{
case DT_DATE: // DATE is converted to string by C API
case DT_TIME: // TIME is converted to string by C API
case DT_TIMESTAMP: // TIMESTAMP is converted to string by
C API
case DT_DECIMAL: // DECIMAL is converted to string by C
API
col_info[i].column_type = DT_FIXCHAR;
break;
case DT_FLOAT: // FLOAT is converted to double by C API
col_info[i].column_type = DT_DOUBLE;
break;
case DT_BIT: // BIT is converted to tinyint by C API
col_info[i].column_type = DT_TINYINT;
break;
}
col_info[i].column_width = info.max_size;
col_info[i].column_index = i + 1; // column indices are origin
1
col_info[i].column_can_be_null = info.nullable;
}
}
// send the result set description
if( extapi->set_value( arg_handle,
EXTFN_RESULT_SET_ARG_NUM,
(an_extfn_value *)&rs_info,
EXTFN_RESULT_SET_DESCRIBE ) == 0 )
{
// failed
free( col_info );
free( col_data );
return;
}
Once the result set has been described, the result set rows can be returned. The following code
fragment shows how to return the rows of the result set. It uses the SAP Sybase IQ C API to
fetch the rows for a SQL query that was executed previously by the C API. The rows returned
by the SAP Sybase IQ C API are sent back, one at a time, to the calling environment. The array
of column data value structures must be filled in before returning each row. The column data
value structure consists of a column index, a pointer to a data value, a data length, and an
append flag.
a_sqlany_data_value *value = (a_sqlany_data_value *)
malloc( columns * sizeof(a_sqlany_data_value) );
If the database server fails to start Java then the problem probably occurs because the database
server is not able to locate the Java executable. In this case, you should execute an ALTER
EXTERNAL ENVIRONMENT statement to explicitly set the location of the Java executable.
Make sure to include the executable file name.
ALTER EXTERNAL ENVIRONMENT JAVA
LOCATION 'java-path';
For example:
ALTER EXTERNAL ENVIRONMENT JAVA
LOCATION 'c:\\jdk1.6.0\\jre\\bin\\java.exe';
You can query the location of the Java VM that the database server will use by executing the
following SQL query:
SELECT db_property('JAVAVM');
Note that the START EXTERNAL ENVIRONMENT JAVA statement is not necessary other than
to verify that the database server can start the Java VM. In general, making a Java stored
procedure or function call starts the Java VM automatically.
Similarly, the STOP EXTERNAL ENVIRONMENT JAVA statement is not necessary to stop an
instance of Java since the instance automatically goes away when the all connections to the
database have terminated. However, if you are completely done with Java and you want to
make it possible to free up some resources, then the STOP EXTERNAL ENVIRONMENT JAVA
statement decrements the usage count for the Java VM.
Once you have verified that the database server can start the Java VM executable, the next
thing to do is to install the necessary Java class code into the database. Do this by using the
INSTALL JAVA statement. For example, you can execute the following statement to install a
Java class from a file into the database.
INSTALL JAVA
NEW
FROM FILE 'java-class-file';
You can also install a Java JAR file into the database.
INSTALL JAVA
NEW
JAR 'jar-name'
FROM FILE 'jar-file';
To remove a Java class from the database, use the REMOVE JAVA statement, as follows:
REMOVE JAVA CLASS java-class
To remove a Java JAR from the database, use the REMOVE JAVA statement, as follows:
REMOVE JAVA JAR 'jar-name'
To modify existing Java classes, you can use the UPDATE clause of the INSTALL JAVA
statement, as follows:
INSTALL JAVA
UPDATE
FROM FILE 'java-class-file'
You can also update existing Java JAR files in the database.
INSTALL JAVA
UPDATE
JAR 'jar-name'
FROM FILE 'jar-file';
Once the Java class is installed in the database, you can then create stored procedures and
functions to interface to the Java methods. The EXTERNAL NAME string contains the
information needed to call the Java method and to return OUT parameters and return values.
The LANGUAGE attribute of the EXTERNAL NAME clause must specify JAVA. The format of
the EXTERNAL NAME clause is:
EXTERNAL NAME 'java-call' LANGUAGE JAVA
java-call :
[package-name.]class-name.method-name method-signature
method-signature :
( [ field-descriptor, ... ] ) return-descriptor
The following procedure creates an interface to a Java method. The Java method does not
return any value (V).
CREATE PROCEDURE insertfix()
EXTERNAL NAME 'JDBCExample.InsertFixed()V'
LANGUAGE JAVA;
The following procedure creates an interface to a Java method that has a String ([Ljava/lang/
String;) input argument. The Java method does not return any value (V).
CREATE PROCEDURE InvoiceMain( IN arg1 CHAR(50) )
EXTERNAL NAME 'Invoice.main([Ljava/lang/String;)V'
LANGUAGE JAVA;
The following procedure creates an interface to a Java method Invoice.init which takes
a string argument (Ljava/lang/String;), a double (D), another string argument (Ljava/lang/
String;), and another double (D), and returns no value (V).
CREATE PROCEDURE init( IN arg1 CHAR(50),
IN arg2 DOUBLE,
IN arg3 CHAR(50),
IN arg4 DOUBLE)
EXTERNAL NAME 'Invoice.init(Ljava/lang/String;DLjava/lang/
String;D)V'
LANGUAGE JAVA
The following Java example contains the function main which takes a string argument and
writes it to the database server messages window. It also contains the function whare that
returns a Java String.
import java.io.*;
The Java code above is placed in the file Hello.java and compiled using the Java compiler.
The class file that results is loaded into the database as follows.
INSTALL JAVA
NEW
FROM FILE 'Hello.class';
Using Interactive SQL, the stored procedure that will interface to the method main in the
class Hello is created as follows:
CREATE PROCEDURE HelloDemo( IN name LONG VARCHAR )
EXTERNAL NAME 'Hello.main([Ljava/lang/String;)V'
LANGUAGE JAVA;
If you check the database server messages window, you will find the message written there.
All output to System.out is redirected to the server messages window.
Using Interactive SQL, the function that will interface to the method whare in the class
Hello is created as follows:
CREATE FUNCTION Whare()
RETURNS LONG VARCHAR
EXTERNAL NAME 'Hello.whoAreYou(V)Ljava/lang/String;'
LANGUAGE JAVA;
You should see the response in the Interactive SQL Results window.
In attempting to troubleshoot why a Java external environment did not start, that is, if the
application gets a "main thread not found" error when a Java call is made, the DBA
should check the following:
• If the Java VM is a different bitness than the database server, then ensure that the client
libraries with the same bitness as the VM are installed on the database server machine.
• Ensure that the sajdbc.jar and dbjdbc12/libdbjdbc12 shared objects are
from the same software build.
• If more than one sajdbc.jar are on the database server machine, make sure they are all
synchronized to the same software version.
• If the database server machine is very busy, then there is a chance the error is being
reported due to a timeout.
See also
• INSTALL JAVA Statement on page 358
• CREATE PROCEDURE Statement (Java UDF) on page 361
• CREATE FUNCTION Statement (Java UDF) on page 363
• REMOVE Statement on page 367
• START JAVA Statement on page 368
• STOP JAVA Statement on page 369
See also
• INSTALL JAVA Statement on page 358
1. Connect to the database as a user with the MANAGE ANY EXTERNAL OBJECT system
privilege.
2. Execute the following statement:
INSTALL JAVA NEW
FROM FILE 'path\\ClassName.class';
path is the directory where the class file is located, and ClassName.class is the
name of the class file.
The double backslash ensures that the backslash is not treated as an escape character.
For example, to install a class in a file named Utility.class, held in the directory
c:\source, you would execute the following statement:
INSTALL JAVA NEW
FROM FILE 'c:\\source\\Utility.class';
If you use a relative path, it must be relative to the current working directory of the database
server.
See also
• External Environment Restrictions on page 331
BIGINT long
BINARY byte[ ]
BIT boolean
CHAR String
DATE java.sql.Date
DECIMAL java.math.BigDecimal
DOUBLE double
IMAGE byte[ ]
INTEGER int
MONEY java.math.BigDecimal
NUMERIC java.math.BigDecimal
REAL float
SMALLINT short
SMALLMONEY java.math.BigDecimal
TEXT String
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp
TINYINT byte
VARBINARY byte[ ]
VARCHAR String
String VARCHAR
String TEXT
java.math.BigDecimal NUMERIC
java.math.BigDecimal MONEY
java.math.BigDecimal SMALLMONEY
boolean BIT
byte TINYINT
short SMALLINT
int INTEGER
long BIGINT
float REAL
double DOUBLE
byte[ ] IMAGE
java.sql.Date DATE
java.sql.Time TIME
java.sql.Timestamp DATETIME/TIMESTAMP
java.lang.Double DOUBLE
java.lang.Float REAL
java.lang.Integer INTEGER
java.lang.Long BIGINT
Prerequisites
• You are familiar with Java and can compile a .java file. You know where the
resulting .class file will reside on the file system.
• You are familiar with Interactive SQL. You can connect to the iqdemo database from
Interactive SQL, and can issue the START EXTERNAL ENVIRONMENT JAVA command
from Interactive SQL.
Task
Use this task as template when creating your own Java UDFs.
This creates the Java class HelloJavaUDF with a static method helloJava. The
method takes a single string argument and returns a string.
2. Compile HellowJavaUDF.java:
javac <pathtojavafile>/HelloJavaUDF.java
3. In Interactive SQL, connect to the iqdemo database.
4. In Interactive SQL, install the class file onto the server:
Example:
INSTALL JAVA NEW FROM FILE 'd:/mydirectory/
HelloJavaUDF.class'
See also
• SQL to Java Data Type Conversion on page 348
• Java to SQL Data Type Conversion on page 349
return a + b;
}
}
public class Sample {
public static int add( int a, int b ){
return new java.lang.Integer(a + b);
}
}
2. Execute the SQL statement to deploy the Java class to the database.
INSTALL JAVA NEW FROM FILE 'd:\\java\\samples\\Sample.class'
3. Create the SQL function that maps to the Java method “Sample.add( int,
int)”.
CREATE FUNCTION sample_add_int (IN a int, IN b int)
RETURNS int
EXTERNAL NAME 'Sample.add(II)I'
LANGUAGE JAVA
4. Use the SQL function in a SELECT statement.
SELECT sample_add_int( ID, ID ) from Customers WHERE ID < 110
5. Remove a Java class from the database.
REMOVE JAVA CLASS ‘Sample’
6. Update a java class in the database.
INSTALL JAVA UPDATE FROM FILE 'd:\\java\\samples\\Sample.class'
INSTALL JAVA JAR UPDATE FROM FILE 'd:\\java\\samples\\Sample.jar'
Prerequisites
• You are familiar with Java and can compile a .java file. You know where the
resulting .class file will reside on the file system.
• You are familiar with Interactive SQL. You can connect to the iqdemo database from
Interactive SQL, and can issue the START EXTERNAL ENVIRONMENT JAVA command
from Interactive SQL.
Task
if ( start < 1 )
{
start = 1;
}
try {
if ( in != null )
{
rc = in.substring( start, endindex );
}
} catch ( IndexOutOfBoundsException ex )
{
System.out.println("ScalarTestFunctions:
my_java_substr("+in+","+start+","+length+")
failed");
System.out.println(ex);
}
return rc;
}
2. In Interactive SQL, connect to the iqdemo database.
3. In Interactive SQL, install the class file onto the server:
INSTALL JAVA NEW FROM FILE '<pathtofile>/
MyJavaSubstr.class'
4. In Interactive SQL, create the function definition:
CREATE or REPLACE FUNCTION java_substr(IN a VARCHAR(255), IN b
INT, IN c INT )
RETURNS VARCHAR(255)
EXTERNAL NAME
'example.MyJavaSubstr.my_java_substr(Ljava/lang/
String;II)Ljava/lang/String;'
LANGUAGE JAVA
Notice the code snippet Ljava/lang/String;II indicating parameter types String, int,
int.
5. In Interactive SQL, use the Java UDF in a query against the iqdemo database:
select GivenName, java_substr(Surname,1,1) from Customers where
lcase(java_substr(Surname,1,1)) = 'a';
Prerequisites
• You are familiar with Java and can compile a .java file. You know where the
resulting .class file will reside on the file system.
• You are familiar with Interactive SQL. You can connect to the iqdemo database from
Interactive SQL, and can issue the START EXTERNAL ENVIRONMENT JAVA command
from Interactive SQL.
Task
This example executes a Java row generator (RowGenerator) that takes a single integer input
and returns that number of rows in a result set. The result set has two columns: one INTEGER
and one VARCHAR. The RowGenerator relies on two utility classes:
• example.ResultSetImpl
• example.ResultSetMetaDataImpl
These are simple implementations of the java.sql.ResultSet interface and
java.sql.ResultSetMetaData interface.
import java.sql.*;
ResultSetImpl rs = null;
try {
rs = new ResultSetImpl( (ResultSetMetaData)rsmd );
rs.beforeFirst(); // Make sure we are at the beginning.
} catch( Exception e ) {
System.out.println( "Error: couldn't create result set." );
System.out.println( e.toString() );
}
try {
rs.beforeFirst(); // rewind the result set so that the server gets
it from the beginning.
} catch( Exception e ) {
System.out.println( e.toString() );
}
rset[0] = rs; // assign the result set to the 1st of the passed in
array.
}
}
2. Compile RowGenerator.java, ResultSetImpl.java, and
ResultSetMetaData.java. The Windows directory %ALLUSERSPROFILE%
\samples\java ($IQDIR15/samples/java on UNIX) contains
ResultSetImpl.java and ResultSetMetaData.java.
javac <pathtojavafile>/ResultSetMetaDataImpl.java
javac <pathtojavafile>/ResultSetImpl.java
javac <pathtojavafile>/RowGenerator.java
3. In Interactive SQL, connect to the iqdemo database.
4. In Interactive SQL, install the three class files:
INSTALL JAVA NEW FROM FILE '<pathtofile>/
ResultSetMataDataImpl.class'
INSTALL JAVA NEW FROM FILE '<pathtofile>/
ResultSetImpl.class'
Note: The RESULT set has two columns; one INTEGER and the other VARCHAR(255).
The Java prototype has two arguments; one INT (I) and the other an array of
java.sql.ResultSets ([Ljava/sql/ResultSet;). The Java prototype
shows the function returning Void(V).
6. In Interactive SQL, use the Java table UDF in a query against the iqdemo database:
SELECT * from rowGenerator(5);
The query returns five rows of two columns.
See also
• SQL to Java Data Type Conversion on page 348
• Java to SQL Data Type Conversion on page 349
}
}
2. SQL statement deploying the Java class to the database:
INSTALL JAVA NEW FROM FILE 'd:\\java\\samples\\Sample.class'
3. SQL procedure mapping to the Java method
Sample.return_rset( java.sql.ResultSet):
CREATE PROCEDURE sample_result_set()
RESULT ( ID int )
DYNAMIC RESULT SETS 1
EXTERNAL NAME 'Sample.return_rset([Ljava/sql/ResultSet;)V'
LANGUAGE JAVA
4. SQL procedure in a SELECT statement:
SELECT * from sample_result_set( ) where ID < 110
System.out.println( e.toString() );
}
rset[0] = rs;
}
2. Java code for java creation of a return_rset method, for non-numerical values:
public static void char_result_udf( java.lang.String s, ResultSet
rset[]) {
// Create the meta data needed for the result set
ResultSetMetaDataImpl rsmd = new ResultSetMetaDataImpl(1);
rsmd.setColumnType(1, Types.CHAR);
if(s.length()==0){
rsmd.setColumnDisplaySize(1, 1);
} else {
rsmd.setColumnDisplaySize(1,s.length() );
}
rsmd.setColumnName(1,"c1");
rsmd.setColumnLabel(1,"c1");
rsmd.setTableName(1,"my_string");
Syntax
INSTALL JAVA [ install-mode ] [ JAR jar-name ]
FROM source
Parameters
(back to top) on page 358
• NEW – (default) requires that the referenced Java classes be new classes, rather than
updates of currently installed classes. An error occurs if a class with the same name exists
in the database and the NEW install mode clause is used
• UPDATE – an install mode of specifies that the referenced Java classes may include
replacements for Java classes already installed in the given database.
• JAR – a character string value of up to 255 bytes that is used to identify the retained JAR in
subsequent INSTALL, UPDATE, and REMOVE statements. jar-name or text-pointer must
designate a JAR file or a column containing a JAR. JAR files typically have extensions
of .jar or .zip.
Installed JAR and zip files can be compressed or uncompressed. However, JAR files
produced by the Sun JDK jar utility are not supported. Files produced by other zip utilities
are supported.
If the JAR option is specified, then the JAR is retained as a JAR after the classes that it
contains have been installed. That JAR is the associated JAR of each of those classes. The
set of JARs installed in a database with the JAR clause are called the retained JARs of the
database.
Retained JARs are referenced in INSTALL and REMOVE statements. Retained JARs have
no effect on other uses of Java-SQL classes. Retained JARs are used by the SQL system for
requests by other systems for the class associated with given data. If a requested class has
an associated JAR, the SQL system can supply that JAR, rather than the individual class.
• source – specifies the location of the Java classes to be installed and must identify either a
class file or a JAR file.
The formats supported for file-name include fully qualified file names, such as 'c:\libs
\jarname.jar' and '/usr/u/libs/jarname.jar', and relative file names,
which are relative to the current working directory of the database server.
The class definition for each class is loaded by the VM of each connection the first time
that class is used. When you INSTALL a class, the VM on your connection is implicitly
restarted. Therefore, you have immediate access to the new class, whether the INSTALL
uses an install-mode clause of NEW or UPDATE.
For other connections, the new class is loaded the next time a VM accesses the class for the
first time. If the class is already loaded by a VM, that connection does not see the new class
until the VM is restarted for that connection (for example, with a STOP JAVA and START
JAVA).
Examples
(back to top) on page 358
• Example 1 – install the user-created Java class named “Demo” by providing the file name
and location of the class:
INSTALL JAVA NEW
FROM FILE 'D:\JavaClass\Demo.class'
After installation, the class is referenced using its name. Its original file path location is no
longer used. For example, this statement uses the class installed in the previous statement:
CREATE VARIABLE d Demo
If the Demo class was a member of the package sybase.work, the fully qualified name of
the class must be used:
CREATE VARIABLE d sybase.work.Demo
• Example 2 – install all the classes contained in a zip file and associate them within the
database with a JAR file name:
INSTALL JAVA
JAR 'Widgets'
FROM FILE 'C:\Jars\Widget.zip'
The location of the zip file is not retained and classes must be referenced using the fully
qualified class name (package name and class name).
Usage
(back to top) on page 358
Only new connections established after installing the class, or that use the class for the first
time after installing the class, use the new definition. Once the Java VM loads a class
definition, it stays in memory until the connection closes.
If you have been using a Java class or objects based on a class in the current connection, you
need to disconnect and reconnect to use the new class definition.
Standards
(back to top) on page 358
• SQL—Vendor extension to ISO/ANSI SQL grammar.
• SAP Sybase Database product—Not supported by Adaptive Server.
Permissions
(back to top) on page 358
• Requires the MANAGE ANY EXTERNAL OBJECT system privilege and a newer
version of the compiled class file or JAR file available in a file on disk.
• All installed classes can be referenced in any way by any user.
Quick Links:
Go to Parameters on page 362
Go to Usage on page 362
Go to Standards on page 362
Go to Permissions on page 363
Syntax
Syntax 1 – For a query referencing at least one SAP Sybase IQ table:
CREATE[ OR REPLACE ] PROCEDURE
[ owner.]procedure-name ( [ parameter, …] )
[ RESULT (result-column, ...)]
[ SQL SECURITY { INVOKER | DEFINER } ]
EXTERNAL NAME ‘java-call’ [ LANGUAGE java ] }
Parameters
(back to top) on page 361
• java – DISALLOW is the default. ALLOW indicates that server-side connections are
allowed.
Note: Do not specify ALLOW unless necessary. A setting of ALLOW slows down certain
types of SAP Sybase IQ table joins. If you change a procedure definition from ALLOW to
DISALLOW, or vice-versa, the change will not be recognized until you make a new
connection.
Do not use UDFs with both ALLOW SERVER SIDE REQUESTS and DISALLOW
SERVER SIDE REQUESTS in the same query.
Usage
(back to top) on page 361
If your query references SAP Sybase IQ tables, note that different syntax and parameters
apply compared to a query that references only catalog store tables.
Java table UDFs are only supported in the FROM clause.
For Java table functions, exactly one result set is allowed. If the Java table functions are joined
with an SAP Sybase IQ table or if a column from an SAP Sybase IQ table is an argument to the
Java table function then only one result set is supported.
If the Java table function is the only item in the FROM clause then N number of result sets are
allowed.
Standards
(back to top) on page 361
• SQL—ISO/ANSI SQL compliant.
• SAP Sybase Database product—The Transact-SQL CREATE PROCEDURE statement is
different.
• SQLJ—The syntax extensions for Java result sets are as specified in the proposed SQLJ1
standard.
Permissions
(back to top) on page 361
Unless creating a temporary procedure, a user must have the CREATE PROCEDURE system
privilege to create a procedure for themselves. To create UDF procedure for others, a user must
specify an owner and have either the CREATE ANY PROCEDURES or CREATE ANY
OBJECT system privilege. If a procedure has an external reference, a user must also have the
CREATE EXTERNAL REFERENCE system privilege, in addition to the previously
mentioned system privileges, regardless of whether or not they are the owner of procedure.
You can avoid this from happening by doing one of the following:
• ensure that temporary tables used in this way are defined consistently
• consider using a global temporary table instead
Syntax
CREATE [ OR REPLACE | TEMPORARY ] FUNCTION [ owner.]function-name
( [ parameter on page 364, ...] )
[ SQL SECURITY { INVOKER | DEFINER } ]
RETURNS data-type
ON EXCEPTION RESUME
| [ NOT ] DETERMINISTIC
{ compound-statement | AS tsql-compound-statement on page 364
| EXTERNAL NAME 'java-call on page 364' LANGUAGE JAVA [ ALLOW | DISALLOW
SERVER SIDE REQUESTS ] environment-name}
Parameters
(back to top) on page 363
• CREATE [ OR REPLACE ] – parameter names must conform to the rules for database
identifiers. They must have a valid SQL data type and be prefixed by the keyword IN,
signifying that the argument is an expression that provides a value to the function.
The CREATE clause creates a new function, while the OR REPLACE clause replaces an
existing function with the same name. When a function is replaced, the definition of the
function is changed but the existing permissions are preserved. You cannot use the OR
REPLACE clause with temporary functions.
• TEMPORARY – the function is visible only by the connection that created it, and that it is
automatically dropped when the connection is dropped. Temporary functions can also be
explicitly dropped. You cannot perform ALTER, GRANT, or REVOKE operations on them,
and unlike other functions, temporary functions are not recorded in the catalog or
transaction log.
Temporary functions execute with the permissions of their creator (current user), and can
only be owned by their creator. Therefore, do not specify owner when creating a temporary
function. They can be created and dropped when connected to a read-only database.
• SQL SECURITY – defines whether the function is executed as the INVOKER, the user
who is calling the function, or as the DEFINER, the user who owns the function. The
default is DEFINER.
When INVOKER is specified, more memory is used because annotation must be done for
each user that calls the procedure. Also, name resolution is done as the invoker as well.
Therefore, take care to qualify all object names (tables, procedures, and so on) with their
appropriate owner.
• data-type – LONG BINARY and LONG VARCHAR are not permitted as return-value
data types.
• compound-statement – a set of SQL statements bracketed by BEGIN and END, and
separated by semicolons. See BEGIN … END Statement.
• tsql-compound-statement – a batch of Transact-SQL statements.
• [NOT] DETERMINISTIC – function is re-evaluated each time it is called in a query. The
results of functions not specified in this manner may be cached for better performance, and
re-used each time the function is called with the same parameters during query evaluation.
Functions that have side effects, such as modifying the underlying data, should be declared
as NOT DETERMINISTIC. For example, a function that generates primary key values
and is used in an INSERT … SELECT statement should be declared NOT
DETERMINISTIC:
CREATE FUNCTION keygen( increment INTEGER )
RETURNS INTEGER
NOT DETERMINISTIC
BEGIN
DECLARE keyval INTEGER;
UPDATE counter SET x = x + increment;
SELECT counter.x INTO keyval FROM counter;
RETURN keyval
END
INSERT INTO new_table
SELECT keygen(1), ...
FROM old_table
Functions may be declared as DETERMINISTIC if they always return the same value for
given input parameters. All user-defined functions are treated as deterministic unless they
are declared NOT DETERMINISTIC. Deterministic functions return a consistent result
for the same parameters and are free of side effects. That is, the database server assumes
that two successive calls to the same function with the same parameters will return the
same result without unwanted side-effects on the semantics of the query.
• LANGUAGE JAVA – a wrapper around a Java method. For information on calling Java
procedures, see CREATE PROCEDURE Statement.
• environment-name – a wrapper around a Java method.
The DISALLOW clause is the default. The ALLOW clause indicates that server-side
connections are allowed.
Note: Do not specify the ALLOW clause unless necessary. ALLOW slows down certain
types of SAP Sybase IQ table joins. Do not use UDFs with both the ALLOW and
DISALLOW SERVER SIDE REQUESTS clauses in the same query.
Examples
(back to top) on page 363
• Example 1 – creates an external function written in Java:
CREATE FUNCTION dba.encrypt( IN name char(254) )
RETURNS VARCHAR
EXTERNAL NAME
'Scramble.encrypt (Ljava/lang/String;)Ljava/lang/String;'
LANGUAGE JAVA
Usage
(back to top) on page 363
When functions are executed, not all parameters need to be specified. If a default value is
provided in the CREATE FUNCTION statement, missing parameters are assigned the default
values. If an argument is not provided by the caller and no default is set, an error is given.
Standards
(back to top) on page 363
• SQL—ISO/ANSI SQL compliant.
• SAP Sybase Database product—Not supported by Adaptive Server.
Permissions
(back to top) on page 363
For function to be owned by self – Requires the CREATE PROCEDURE system privilege
For function to be owned by any user – Requires one of:
• CREATE ANY PROCEDURES system privilege.
REMOVE Statement
Removes a class, a package, or a JAR file from a database. Removed classes are no longer
available for use as a variable type. Any class, package, or JAR to be removed must already be
installed.
Quick Links:
Go to Parameters on page 367
Go to Examples on page 367
Go to Standards on page 368
Go to Permissions on page 368
Syntax
REMOVE JAVA classes_to_remove
classes_to_remove
{ CLASS java_class_name [, java_class_name ]…
| PACKAGE java_package_name [, java_package_name ]…
| JAR jar_name [, jar_name ]… [ RETAIN CLASSES ] }
Parameters
(back to top) on page 367
• java_class_name – he name of one or more Java classes to be removed. Those classes
must be installed classes in the current database.
• java_package_name – he name of one or more Java packages to be removed. Those
packages must be the name of packages in the current database.
• jar_name – a character string value of maximum length 255. Each jar_name must be
equal to the jar_name of a retained JAR in the current database. Equality of jar_name is
determined by the character string comparison rules of the SQL system.
• RETAIN CLASSES – the specified JARs are no longer retained in the database, and the
retained classes have no associated JAR. If RETAIN CLASSES is specified, this is the
only action of the REMOVE statement.
Examples
(back to top) on page 367
• Example 1 – remove a Java class named “Demo” from the current database:
REMOVE JAVA CLASS Demo
Standards
(back to top) on page 367
• SQL—Vendor extension to ISO/ANSI SQL grammar.
• SAP Sybase Database product—Not supported by Adaptive Server. A similar feature is
available in an Adaptive Server-compatible manner using nested transactions.
Permissions
(back to top) on page 367
Requires one of:
• MANAGE ANY EXTERNAL OBJECT system privilege.
• You own the object.
Syntax
START EXTERNAL ENVIRONMENT JAVA
Examples
(back to top) on page 368
• Example 1 – start the Java VM:
START EXTERNAL ENVIRONMENT JAVA
Standards
(back to top) on page 368
• SQL—Vendor extension to ISO/ANSI SQL grammar.
• SAP Sybase Database product—Not applicable.
Permissions
(back to top) on page 368
None
Syntax
STOP EXTERNAL ENVIRONMENT JAVA
Standards
(back to top) on page 369
• SQL—Vendor extension to ISO/ANSI SQL grammar.
• SAP Sybase Database product—Not applicable.
Permissions
(back to top) on page 369
None
1. Perl must be installed on the database server computer and the database server must be able
to locate the Perl executable.
1. The DBD::SQLAnywhere driver must be installed on the database server computer.
2. On Windows, Microsoft Visual Studio must also be installed. This is a prerequisite since it
is necessary for installing the DBD::SQLAnywhere driver.
In addition to the above prerequisites, the database administrator must also install the Perl
External Environment module.
To install the external environment module (Windows):
• Run the following commands from the SDK\PerlEnv subdirectory:
perl Makefile.PL
nmake
nmake install
To install the external environment module (UNIX):
• Run the following commands from the sdk/perlenv subdirectory:
perl Makefile.PL
make
make install
Once the Perl external environment module has been built and installed, the Perl in the
database support can be used.
To use Perl in the database, make sure that the database server is able to locate and start the Perl
executable. Verify that this can be done by executing:
START EXTERNAL ENVIRONMENT PERL;
If the database server fails to start Perl, then the problem probably occurs because the database
server is not able to locate the Perl executable. In this case, you should execute an ALTER
EXTERNAL ENVIRONMENT statement to explicitly set the location of the Perl executable.
Make sure to include the executable file name.
ALTER EXTERNAL ENVIRONMENT PERL
LOCATION 'perl-path';
For example:
ALTER EXTERNAL ENVIRONMENT PERL
LOCATION 'c:\\Perl\\bin\\perl.exe';
Note that the START EXTERNAL ENVIRONMENT PERL statement is not necessary other than
to verify that the database server can start Perl. In general, making a Perl stored procedure or
function call starts Perl automatically.
Similarly, the STOP EXTERNAL ENVIRONMENT PERL statement is not necessary to stop an
instance of Perl since the instance automatically goes away when the connection terminates.
However, if you are completely done with Perl and you want to free up some resources, then
the STOP EXTERNAL ENVIRONMENT PERL statement releases the Perl instance for your
connection.
Once you have verified that the database server can start the Perl executable, the next thing to
do is to install the necessary Perl code into the database. Do this by using the INSTALL
statement. For example, you can execute the following statement to install a Perl script from a
file into the database.
INSTALL EXTERNAL OBJECT 'perl-script'
NEW
FROM FILE 'perl-file'
ENVIRONMENT PERL;
Perl code also can be built and installed from an expression, as follows:
INSTALL EXTERNAL OBJECT 'perl-script'
NEW
FROM VALUE 'perl-statements'
ENVIRONMENT PERL;
Perl code also can be built and installed from a variable, as follows:
CREATE VARIABLE PerlVariable LONG VARCHAR;
SET PerlVariable = 'perl-statements';
INSTALL EXTERNAL OBJECT 'perl-script'
NEW
FROM VALUE PerlVariable
ENVIRONMENT PERL;
To remove Perl code from the database, use the REMOVE statement, as follows:
REMOVE EXTERNAL OBJECT 'perl-script'
To modify existing Perl code, you can use the UPDATE clause of the INSTALL EXTERNAL
OBJECT statement, as follows:
INSTALL EXTERNAL OBJECT 'perl-script'
UPDATE
FROM FILE 'perl-file'
ENVIRONMENT PERL
INSTALL EXTERNAL OBJECT 'perl-script'
UPDATE
FROM VALUE 'perl-statements'
ENVIRONMENT PERL
SET PerlVariable = 'perl-statements';
INSTALL EXTERNAL OBJECT 'perl-script'
UPDATE
FROM VALUE PerlVariable
ENVIRONMENT PERL
Once the Perl code is installed in the database, you can then create the necessary Perl stored
procedures and functions. When creating Perl stored procedures and functions, the
LANGUAGE is always PERL and the EXTERNAL NAME string contains the information
needed to call the Perl subroutines and to return OUT parameters and return values. The
following global variables are available to the Perl code on each call:
• $sa_perl_return – This is used to set the return value for a function call.
• $sa_perl_argN – where N is a positive integer [0 .. n]. This is used for passing the SQL
arguments down to the Perl code. For example, $sa_perl_arg0 refers to argument 0,
$sa_perl_arg1 refers to argument 1, and so on.
• $sa_perl_default_connection – This is used for making server-side Perl calls.
• $sa_output_handle – This is used for sending output from the Perl code to the database
server messages window.
A Perl stored procedure can be created with any set of data types for input and output
arguments, and for the return value. However, all non-binary data types are mapped to strings
when making the Perl call while binary data is mapped to an array of numbers. A simple Perl
example follows:
INSTALL EXTERNAL OBJECT 'SimplePerlExample'
NEW
FROM VALUE 'sub SimplePerlSub{
return( ($_[0] * 1000) +
($_[1] * 100) +
($_[2] * 10) +
$_[3] );
}'
ENVIRONMENT PERL;
The following Perl example takes a string and writes it to the database server messages
window:
INSTALL EXTERNAL OBJECT 'PerlConsoleExample'
NEW
FROM VALUE 'sub WriteToServerConsole { print $sa_output_handle
$_[0]; }'
ENVIRONMENT PERL;
To use server-side Perl, the Perl code must use the $sa_perl_default_connection variable. The
following example creates a table and then calls a Perl stored procedure to populate the table:
CREATE TABLE perlTab(c1 int, c2 char(128));
CALL PerlPopulateTable();
install prebuilt modules, copy the appropriate driver module to your PHP extensions directory
(which can be found in php.ini). On UNIX, you can also use a symbolic link.
To install the external environment module (Windows):
1. Locate the php.ini file for your PHP installation, and open it in a text editor. Locate the
line that specifies the location of the extension_dir directory. If extension_dir
is not set to any specific directory, it is a good idea to set it to point to an isolated directory
for better system security.
2. Copy the desired external environment PHP module from the installation directory to your
PHP extensions directory. Change the x.y to reflect the version you have selected.
copy "%SQLANY12%\Bin32\php-5.x.y_sqlanywhere_extenv12.dll"
php-dir\ext
3. Add the following line to the Dynamic Extensions section of the php.ini file to load the
external environment PHP module automatically. Change the x.y to reflect the version you
have selected.
extension=php-5.x.y_sqlanywhere_extenv12.dll
To use PHP in the database, the database server must be able to locate and start the PHP
executable. You can verify if the database server is able to locate and start the PHP executable
by executing the following statement:
START EXTERNAL ENVIRONMENT PHP;
If you see a message that states that 'external executable' could not be found, then the problem
is that the database server is not able to locate the PHP executable. In this case, you should
execute an ALTER EXTERNAL ENVIRONMENT statement to explicitly set the location of the
PHP executable including the executable name or you should ensure that the PATH
environment variable includes the directory containing the PHP executable.
ALTER EXTERNAL ENVIRONMENT PHP
LOCATION 'php-path';
For example:
ALTER EXTERNAL ENVIRONMENT PHP
LOCATION 'c:\\php\\php-5.2.6-win32\\php.exe';
The START EXTERNAL ENVIRONMENT PHP statement is not necessary other than to verify
that the database server can start PHP. In general, making a PHP stored procedure or function
call starts PHP automatically.
Similarly, the STOP EXTERNAL ENVIRONMENT PHP statement is not necessary to stop an
instance of PHP since the instance automatically goes away when the connection terminates.
However, if you are completely done with PHP and you want to free up some resources, then
the STOP EXTERNAL ENVIRONMENT PHP statement releases the PHP instance for your
connection.
Once you have verified that the database server can start the PHP executable, the next thing to
do is to install the necessary PHP code into the database. Do this by using the INSTALL
statement. For example, you can execute the following statement to install a particular PHP
script into the database.
INSTALL EXTERNAL OBJECT 'php-script'
NEW
FROM FILE 'php-file'
ENVIRONMENT PHP;
PHP code can also be built and installed from an expression as follows:
INSTALL EXTERNAL OBJECT 'php-script'
NEW
FROM VALUE 'php-statements'
ENVIRONMENT PHP;
PHP code can also be built and installed from a variable as follows:
CREATE VARIABLE PHPVariable LONG VARCHAR;
SET PHPVariable = 'php-statements';
To remove PHP code from the database, use the REMOVE statement as follows:
REMOVE EXTERNAL OBJECT 'php-script';
To modify existing PHP code, you can use the UPDATE clause of the INSTALL statement as
follows:
INSTALL EXTERNAL OBJECT 'php-script'
UPDATE
FROM FILE 'php-file'
ENVIRONMENT PHP;
INSTALL EXTERNAL OBJECT 'php-script'
UPDATE
FROM VALUE 'php-statements'
ENVIRONMENT PHP;
SET PHPVariable = 'php-statements';
INSTALL EXTERNAL OBJECT 'php-script'
UPDATE
FROM VALUE PHPVariable
ENVIRONMENT PHP;
Once the PHP code is installed in the database, you can then go ahead and create the necessary
PHP stored procedures and functions. When creating PHP stored procedures and functions,
the LANGUAGE is always PHP and the EXTERNAL NAME string contains the information
needed to call the PHP subroutines and for returning OUT parameters.
The arguments are passed to the PHP script in the $argv array, similar to the way PHP would
take arguments from the command line (that is, $argv[1] is the first argument). To set an output
parameter, assign it to the appropriate $argv element. The return value is always the output
from the script (as a LONG VARCHAR).
A PHP stored procedure can be created with any set of data types for input or output
arguments. However, the parameters are converted to and from a boolean, integer, double, or
string for use inside the PHP script. The return value is always an object of type LONG
VARCHAR. A simple PHP example follows:
INSTALL EXTERNAL OBJECT 'SimplePHPExample'
NEW
FROM VALUE '<?php function SimplePHPFunction(
$arg1, $arg2, $arg3, $arg4 )
{ return ($arg1 * 1000) +
($arg2 * 100) +
($arg3 * 10) +
$arg4;
} ?>'
ENVIRONMENT PHP;
IN tens INT,
IN ones INT)
RETURNS LONG VARCHAR
EXTERNAL NAME '<file=SimplePHPExample> print SimplePHPFunction(
$argv[1], $argv[2], $argv[3], $argv[4]);'
LANGUAGE PHP;
For PHP, the EXTERNAL NAME string is specified in a single line of SQL.
To use server-side PHP, the PHP code can use the default database connection. To get a handle
to the database connection, call sasql_pconnect with an empty string argument ('' or ""). The
empty string argument tells the PHP driver to return the current external environment
connection rather than opening a new one. The following example creates a table and then
calls a PHP stored procedure to populate the table:
CREATE TABLE phpTab(c1 int, c2 char(128));
CALL PHPPopulateTable();
For PHP, the EXTERNAL NAME string is specified in a single line of SQL. In the above
example, note that the single quotes are doubled-up because of the way quotes are parsed in
SQL. If the PHP source code was in a file, then the single quotes would not be doubled-up.
To return an error back to the database server, throw a PHP exception. The following example
shows how to do this.
CREATE TABLE phpTab(c1 int, c2 char(128));
CALL PHPPopulateTable();
Index
a_v4_extfn_describe_return enumerator 284
_close_extfn
a_v4_extfn_describe_udf_type enumerator 286
v4 API method 324
a_v4_extfn_estimate
_describe_extfn 208, 290
optimizer estimate 306
_enter_state_extfn 291
structure 306
_fetch_block_extfn
a_v4_extfn_license_info 305
v4 API method 322
a_v4_extfn_order_el
_fetch_into_extfn
column order 206
v4 API method 322
structure 206
_finish_extfn 289
a_v4_extfn_orderby_list
_leave_state_extfn 291
order by list 307
_open_extfn
structure 307
v4 API method 321
a_v4_extfn_partitionby_col_num enumerator 307
_rewind_extfn
a_v4_extfn_proc 97
v4 API method 323
external function 288
_start_extfn 289
structure 288
.NET external environment 329
a_v4_extfn_proc_context
convert_value method 300
A external procedure context 292
get_blob method 304
a_v3_extfn API
get_is_cancelled method 298
Upgrading to a_v4_extfn API 16
get_value method 294
a_v4_extfn API
get_value_is_constant method 296
Upgrading from a_v3_extfn API 16
log_message method 299
a_v4_extfn_blob
set_error method 298
blob 199
set_value method 297
blob_length 200
structure 292
close_istream 201
a_v4_extfn_row 309
open_istream 201
a_v4_extfn_row_block 309
release 202
a_v4_extfn_state enumerator 287
structure 199
a_v4_extfn_table
a_v4_extfn_blob_istream
structure 310
blob input stream 203
table 310
get 203
a_v4_extfn_table_context
structure 203
get_blob method 318
a_v4_extfn_col_subset_of_input
structure 311
column values subset 207
table context 311
structure 207
a_v4_extfn_table_func
a_v4_extfn_column_data
structure 319
column data 204
table functions 319
structure 204
aCC
a_v4_extfn_column_list
HP-UX 22
column list 206
Itanium 22
structure 206
aggregate
a_v4_extfn_describe_col_type enumerator 281
calculation context 59
a_v4_extfn_describe_parm_type enumerator 282
v4 API
_close_extfn method 324 X
_fetch_block_extfn method 322
_fetch_into_extfn method 322 x86
_open_extfn method 321 g++ 22
_rewind_extfn method 323 Linux 22
alloc method 301, 302 Solaris 23
backward-compatibility 16 Sun Studio 12 23
close_result_set method 304 Visual Studio 2009 24
fetch_block method 130, 316 Windows 24
fetch_into method 130, 313 xIC
get_option method 301 Linux 22
open_result_set method 303 PowerPC 22
rewind method 318 xlC
set_cannot_be_distributed method 305 AIX 21
v4_extfn_partitionby_col_num 141 PowerPC 21