[UDF系列]如何编写InterBase UDF 之二

( 接上一篇)

如何编写 InterBase UDF

warton 译

** 怎么编写字符串和日期型处理函数的 UDF ** ** 呢? **

下面编写一个“ Left “函数

内存分配问题:

如果你使用 IB(InterBase)5.1 以下版本的话,在你的单元文件中键入下面的声明:

function malloc(Bytes: Integer): Pointer; cdecl; external 'msvcrt.dll';

如果你有 5.5 以上的版本,你就不需要这么做了。这样,先确定 ib_util.pas 文件在你的编译器可以找到的路径中,并且 ib_util.dll 也在你的搜索路径之中。

最简单的方法是放到的库可搜索到的路径。

c:\Program Files\InterBase Corp\InterBase\include

然后复制

c:\Program Files\InterBase Corp\InterBase\lib\ib_util.dll

到你的 windows 系统目录下 ( 典型的是: c:\Windows\System ) 。最后在你的单元文件的 use 子句中将 ib_util.pas加进去

                uses

...,

ib_util;

为什么有如此奇特的内存分配?为什么我不能用 AllocMem分配内存,或者其它方法?问题很简单:你不能,所以不要问!更复杂的问题是每一个编译器使用它喜欢的算法来进行内存管理,这是被操作系统控制着的。例如,VC和Delphi管理内存的方式不同,猜这是为什么?IB是在VC下编译的,在5.5以前的版本中,你必须直接指定运行库。在IB5.5之后,IB给了一个IB调用使得这成为可能。既然这样,那我们继续进行编写字符串操作的函数。

** 构建函数 **

** ** 在新的单元文件中,作如下声明:

function Left(sz: PChar; Cnt: Integer): PChar; cdecl; export;

在函数实现部分:

               (* Return the Cnt leftmost characters of sz *)


function Left(sz: PChar; var Cnt: Integer): PChar;


var


  i: Integer;


begin


  if (sz = nil) then


    result := nil


  else begin


    i := 0;


    while ((sz[i] <> #0) and (i < cnt)) do Inc(i);


    result := ib_util_malloc(i+1);


    Move(sz[0], result[0], i);


    result[i] := #0;


  end;


end;

在你的工程文件中,在“ exports “部分键入:

               exports


               Modulo,


               Left;


 

Now, 再次编译工程项目 ….

现在,为了使用函数,在 ISQL 中重新连接数据库,输入:

                declare external function f_Left

cstring(64), integer

returns cstring(64) free_it

entry_point 'Left' module_name 'dll name minus ".dll"';

测试这个函 ...

select f_Left('Hello', 3) from rdb$database

仍然相当简单,哈?

** 上我们来编写一个时间函数 **


在 IB6 中,有三种不同的时期类型被支持, DATE,TIME, 和 TIMESTAMP ,与 IB5.5 及以前老版本中的相比, TIMESTAMP 的数据类型实质上相当于 IB5.5 的 DATE 类型。

为了在你的程序中 ”decode” 和 ”encode” 这些类型。你应该了解一点 IB API 相关的信息。输入以下代码:

interface


...


 


type


 


  TM = record


    tm_sec : integer;   // Seconds


    tm_min : integer;   // Minutes


    tm_hour : integer;  // Hour (0--23)


    tm_mday : integer;  // Day of month (1--31)


    tm_mon : integer;   // Month (0--11)


    tm_year : integer;  // Year (calendar year minus 1900)


    tm_wday : integer;  // Weekday (0--6) Sunday = 0)


    tm_yday : integer;  // Day of year (0--365)


    tm_isdst : integer; // 0 if daylight savings time is not in effect)


  end;


 


  PTM             = ^TM;


 


  ISC_TIMESTAMP = record


    timestamp_date : Long;


    timestamp_time : ULong;


  end;


 


  PISC_TIMESTAMP = ^ISC_TIMESTAMP;


 


implementation


...


 


procedure isc_encode_timestamp  (tm_date: PTM;


                                                            ib_date: PISC_TIMESTAMP);


                                stdcall; external IBASE_DLL;


 


procedure isc_decode_timestamp  (ib_date: PISC_TIMESTAMP;


                                 tm_date: PTM);


                                stdcall; external IBASE_DLL;


 


 


procedure isc_decode_sql_date   (var ib_date: Long;


                                 tm_date: PTM);


                                stdcall; external IBASE_DLL;


 


procedure isc_encode_sql_date   (tm_date: PTM;


                                 var ib_date: Long);


                                stdcall; external IBASE_DLL;


 


 


 


procedure isc_decode_sql_time   (var ib_date: ULong;


                                 tm_date: PTM);


                                stdcall; external IBASE_DLL;


 


procedure isc_encode_sql_time   (tm_date: PTM;


                                 var ib_date: ULong);


                                stdcall; external IBASE_DLL;

现在我们写日期 UDF:

在单元文件的 interface 部分,输入声明:

function Year(var ib_date: Long): Integer; cdecl; export;


function Hour(var ib_time: ULong): Integer; cdecl; export;

在 implementation( 实现 ) 部分,输入:

function Year(var ib_date: Long): Integer;


var


  tm_date: TM;


begin


  isc_decode_sql_date(@ib_date, @tm_date);


  result := tm_date.tm_year + 1900;


end;


 


function Hour(var ib_time: ULong): Integer;


var


  tm_date: TM;


begin


  isc_decode_sql_time(@ib_time, @tm_date);


  result := tm_date.tm_hour;


end;

最好,在你的工程文件中:在““部分,输入:

exports

Modulo,

Left,

Year,

Hour;

现在编译工程 ...

为了使用这个函数,就像上面那样:用 ISQL连接数据库,输入:

declare external function f_Year


date


returns integer by value


entry_point 'Year' module_name 'dll name minus ".dll"';


 


declare external function f_Hour


time


returns integer by value


entry_point 'Hour' module_name 'dll name minus ".dll"';

最后再测试一下看 !

select f_Year(cast('7/11/00' as date)) from rdb$database

这一部分并非像前面字符串和整数那样操作哪样了,但是还是相当 ...simple,哼!

** 编写 Linux/Unix平台的UDF **

( 未完待续 !!)

Published At
Categories with 数据库类
Tagged with
comments powered by Disqus