Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 12.0.1 » SQL Anywhere 服务器 - 编程 » SQL Anywhere 外部环境支持

 

CLR 外部环境

SQL Anywhere 支持 CLR 存储过程和函数。CLR 存储过程或函数的行为与 SQL 存储过程或函数的行为基本相同,只是过程或函数的代码以 C# 或 Visual Basic 等 .NET 语言编写,并且在数据库服务器外(即在单独的 .NET 可执行文件内)执行过程或函数。每个数据库只有一个此 .NET 可执行文件的实例。执行 CLR 函数和存储过程的所有连接都使用同一个 .NET 可执行实例,但每个连接的命名空间是独立的。静态在连接期间内会一直保持,但在连接之间不共享。仅支持 .NET 版本 2.0。

要调用外部 CLR 函数或过程,需要在定义相应存储过程或函数时指定 EXTERNAL NAME 字符串,确定装载哪个 DLL 以及调用程序集中的哪个函数。此外,在定义存储过程或函数时,还必须指定 LANGUAGE CLR。以下是一个声明示例:

CREATE PROCEDURE clr_stored_proc( 
    IN p1 INT, 
    IN p2 UNSIGNED SMALLINT, 
    OUT p3 LONG VARCHAR) 
EXTERNAL NAME 'MyCLRTest.dll::MyCLRTest.Run( int, ushort, out string )' 
LANGUAGE CLR;

在此示例中,名为 clr_stored_proc 的存储过程在执行时会装载 DLL MyCLRTest.dll 并调用函数 MyCLRTest.Run。clr_stored_proc 过程使用三个 SQL 参数,即两个分别为 INT 类型和 UNSIGNED SMALLINT 类型的 IN 参数和一个 LONG VARCHAR 类型的 OUT 参数。在 .NET 端,这三个参数转换为 int 类型和 ushort 类型的输入参数和 string 类型的输出参数。除了 out 参数,CLR 函数还可以具有 ref 参数。如果相应的存储过程有 INOUT 参数,则用户必须声明 ref CLR 参数。

下表列出了各种 CLR 参数类型以及对应的建议 SQL 数据类型:

CLR 类型 建议的 SQL 数据类型
bool bit
byte tinyint
short smallint
ushort unsigned smallint
int int
uint unsigned int
long bigint
ulong unsigned bigint
decimal numeric
float real
double double
DateTime timestamp
string long varchar
byte[ ] long binary

DLL 的声明可以使用相对路径也可以使用绝对路径。如果指定路径为相对路径,则外部 .NET 可执行文件会在该路径及其它位置搜索 DLL。可执行文件不会在全局程序集高速缓存 (GAC) 中搜索 DLL。

与现有 Java 存储过程和函数一样,CLR 存储过程和函数可以发出返回到数据库的服务器端请求,还可以返回结果集。而且,像 Java 一样,任何输出到 Console.Out 和 Console.Error 的信息都会自动重定向到数据库服务器消息窗口。

关于如何发出服务器端请求以及如何从 CLR 函数或存储过程返回结果集的详细信息,请参见位于 %SQLANYSAMP12%\SQLAnywhere\ExternalEnvironments\CLR 目录下的示例。

在数据库中使用 CLR,需确保数据库服务器能够找到并启动 CLR 可执行文件。通过执行以下语句可以验证数据库服务器是否能够找到并启动 CLR 可执行文件:

START EXTERNAL ENVIRONMENT CLR;

如果数据库服务器未能启动 CLR,则可能是数据库服务器无法找到 CLR 可执行文件。CLR 可执行文件为 dbextclr12.exe。确保此文件位于 %SQLANY12%\CE\Assembly\V2\CE\Assembly\V2\Bin32%SQLANY12%\CE\Assembly\V2\Bin64 文件夹,具体取决于所用数据库服务器的版本。

请注意,除了验证数据库服务器可以启动 CLR 可执行文件外,START EXTERNAL ENVIRONMENT CLR 语句并不是必需的。通常,进行 CLR 存储过程或函数的调用会自动启动 CLR。

类似地,停止 CLR 的实例时 STOP EXTERNAL ENVIRONMENT CLR 语句也不是必需的,因为连接终止时实例会自动消失。然而,如果要彻底离开 CLR 并且想要释放一些资源,STOP EXTERNAL ENVIRONMENT CLR 语句则可以为您的连接释放 CLR 实例。

与 Perl、PHP 和 Java 外部环境不同,CLR 环境不需要在数据库中安装任何内容。因此,使用 CLR 外部环境前,无需执行任何 INSTALL 语句。

下面是一个可以在外部环境中运行、以 C# 编写的函数的示例。

public class StaticTest
{
    private static int val = 0;

    public static int GetValue() {
        val += 1;
        return val;
    }
}

此函数编译到动态链接库后,即可从外部环境调用。数据库服务器会启动名为 dbextclr12.exe 的可执行映像,用以为您装载该动态链接库。SQL Anywhere 附带了多种版本的该可执行文件。例如,在 Windows 中,可以同时拥有 32 位和 64 位的可执行文件。一个用于 32 位版本的数据库服务器,另一个用于 64 位版本的数据库服务器。

要使用 Microsoft C# 编译器将此应用程序构建到动态链接库中,请使用如下的命令。假定上面示例的源代码位于名为 StaticTest.cs 的文件中。

csc /target:library /out:clrtest.dll StaticTest.cs

此命令将编译后的代码放在名为 clrtest.dll 的 DLL 中。要调用编译后的 C# 函数 GetValue,应使用 Interactive SQL 按如下方式定义包装:

CREATE FUNCTION stc_get_value() 
RETURNS INT 
EXTERNAL NAME 'clrtest.dll::StaticTest.GetValue() int' 
LANGUAGE CLR;

对于 CLR,EXTERNAL NAME 字符串以 SQL 的单独一行指定。为了能够找到 DLL,您可能需要在 EXTERNAL NAME 字符串中包含该 DLL 的路径。对于相关程序集(例如,如果 myLib.dll 的代码调用的函数在 myOtherLib.dll 中或以某种方式与其相关),则由 .NET Framework 决定装载依赖性。CLR 外部环境将对指定程序集的装载进行处理,但可能需要执行额外的步骤才能确保装载相关程序集。一种解决方案是,通过使用与 .NET Framework 一起安装的 Microsoft gacutil 实用程序,在全局程序集高速缓存 (GAC) 中注册所有依赖性。对于自定义开发库,gacutil 要求先使用强命名密钥对库进行签名,然后才能在 GAC 中注册这些库。

要执行该编译后 C# 函数示例,请执行以下语句。

SELECT stc_get_value();

每次调用 C# 函数都会生成一个新的整数结果。返回值的顺序是 1、2、3 以此类推。

有关在数据库支持中使用 CLR 的详细信息和示例,请参见位于 %SQLANYSAMP12%\SQLAnywhere\ExternalEnvironments\CLR 目录下的示例。