short (SQL_CALLBACK *get_value) ( void * arg_handle, a_sql_uint32 arg_num, an_extfn_value *value ); |
get_value 回调函数可用于获取传递给作为外部函数接口的存储过程或函数的参数值。如果失败则返回 0;否则返回非零结果。调用 get_value 之后,an_extfn_value 结构的 total_len 字段会包含整个值的长度。piece_len 字段包含作为 get_value 调用结果所获取的那部分的长度。请注意,piece_len 将始终小于或等于 otal_len。小于时,可以调用另一个函数 get_piece 来获得其余部分。请注意,total_len 字段只在初始调用 get_value 后才有效。该字段会由通过调用 get_piece 而更改的 remain_len 字段覆盖。调用 get_value 后,如果打算在以后使用 total_len 字段的值,则应立即将其保留下来。
short (SQL_CALLBACK *get_piece) ( void * arg_handle, a_sql_uint32 arg_num, an_extfn_value *value, a_sql_uint32 offset ); |
如果不能一次性返回整个参数值,则可以反复调用 get_piece 函数来获取参数值的其余部分。
通过调用 get_value 和 get_piece 所返回的所有 piece_len 值的总和将等于调用 get_value 之后 total_len 字段所返回的初始值。调用 get_piece 之后,remain_len 字段会覆盖 total_len,它表示尚未获取的长度。
下面的示例显示如何使用 get_value 和 get_piece 来获取字符串参数的值,如 long varchar 型参数。
假设按如下方式声明了外部函数的包装:
CREATE PROCEDURE mystring( IN instr LONG VARCHAR ) EXTERNAL NAME 'mystring@mystring.dll'; |
为从 SQL 调用外部函数,我们将使用如下的语句。
call mystring('Hello world!'); |
下面是以 C 语言编写的 mystring 函数针对 Windows 操作系统的实现示例:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> #include "extfnapi.h" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } extern "C" __declspec( dllexport ) a_sql_uint32 extfn_use_new_api( void ) { return( EXTFN_API_VERSION ); } extern "C" __declspec( dllexport ) void mystring( an_extfn_api *extapi, void *arg_handle ) { short result; an_extfn_value arg; unsigned offset; char *string; result = extapi->get_value( arg_handle, 1, &arg ); if( result == 0 || arg.data == NULL ) { return; // no parameter or parameter is NULL } string = (char *)malloc( arg.len.total_len + 1 ); offset = 0; for( ; result != 0; ) { if( arg.data == NULL ) break; memcpy( &string[offset], arg.data, arg.piece_len ); offset += arg.piece_len; string[offset] = '\0'; if( arg.piece_len == 0 ) break; result = extapi->get_piece( arg_handle, 1, &arg, offset ); } MessageBoxA( NULL, string, "SQL Anywhere", MB_OK | MB_TASKMODAL ); free( string ); return; } |
short (SQL_CALLBACK *set_value) ( void * arg_handle, a_sql_uint32 arg_num, an_extfn_value *value short append ); |
set_value 回调函数可用于设置 OUT 参数和存储函数的 RETURNS 结果。arg_num 值为 0 时表示设置 RETURNS 值。以下是一个示例。
an_extfn_value retval; retval.type = DT_LONGVARCHAR; retval.data = result; retval.piece_len = retval.len.total_len = (a_sql_uint32) strlen( result ); extapi->set_value( arg_handle, 0, &retval, 0 ); |
set_value 的 append 参数决定所提供的数据是替换 (false) 现有数据,还是附加到 (true) 现有数据之后。在用 append=TRUE
为同一参数调用 set_value 前,必须使用 append=FALSE
调用它。对于固定长度的数据类型,将忽略 append 参数。
要返回 NULL,请将 an_extfn_value 结构的数据字段设置为 NULL。
void (SQL_CALLBACK *set_cancel) ( void *arg_handle, void *cancel_handle ); |
外部函数可以获得 IN 或 INOUT 参数的值,并且可以设置 OUT 参数以及存储函数的 RETURNS 结果。但有一种情况下,获取的参数值可能不再有效,或者值的设置不再必要。这种情况发生在取消一个正在执行的 SQL 语句的时候。这可能是因为应用程序突然与数据库服务器断开连接。要处理这种情况,可以在一个名为 extfn_cancel 的库中定义一个特殊的入口点。定义此函数后,每当取消一个正在运行的 SQL 语句,服务器就会调用该函数。
extfn_cancel 函数通过一个可以以任何合适方式使用的句柄来调用。句柄的典型用途是间接设置一个标志来指示正在调用的 SQL 语句已取消。
传递的句柄值可以由外部库中的函数使用 set_cancel 回调函数来设置。这可由以下代码段来说明。
extern "C" __declspec( dllexport ) void extfn_cancel( void *cancel_handle ) { *(short *)cancel_handle = 1; } extern "C" __declspec( dllexport ) void mystring( an_extfn_api *api, void *arg_handle ) { . . . short canceled = 0; extapi->set_cancel( arg_handle, &canceled ); . . . if( canceled ) |
请注意,设置静态全局 "canceled" 变量是不恰当的,因为当所有连接的所有 SQL 语句都被取消时(通常不会这样),它会被错误的解释。这正是提供 set_cancel 回调函数的原因。在调用 set_cancel 之前务必要初始化 "canceled" 变量。
在外部函数的关键控制点检查 "canceled" 变量的设置是非常重要的。关键控制点包括通过调用外部库来调用 API 函数(如 get_value 和 set_value)的之前和之后。如果设置了变量(调用 extfn_cancel 的结果),外部函数可以采取适当的终止动作。基于前面示例的代码段如下:
if( canceled ) { free( string ); return; } |
任何给定参数的 get_piece 函数只能紧接着相同参数的 get_value 函数被调用。
在 OUT 参数上调用 get_value 将返回设置为参数数据类型的 an_extfn_value 结构的类型字段,以及设置为 NULL 的 an_extfn_value 结构的数据字段。
SQL Anywhere 安装目录 SDK\Include 文件夹中的头文件 extfnapi.h 包含一些附加说明。
下表说明在 an_extfn_api 中定义的函数返回 false 所基于的条件:
函数 | 在以下条件为真时返回 0;否则返回 1 |
---|---|
get_value() |
|
get_piece() |
|
set_value() |
|
Copyright © 2009, iAnywhere Solutions, Inc. - SQL Anywhere 11.0.1 |