Subject | UDF assistance |
---|---|
Author | Adam |
Post date | 2008-12-01T03:18:54Z |
Hello Group,
I am having some difficulty with a small number of UDF calls with
Firebird 2.1.
These have worked for years alongside Firebird 1.5. Furthermore, the
problem is intermittent and difficult to reduce to a simple test case,
as even removing an unrelated join from the query stops the error from
occurring. I do have a reproducable test case, but it involves a 30
line SQL statement and a 1GB database. I think it is better to rather
start with the code I am using to see if there are any obvious errors.
I have not been able to reproduce the error using "select
FB_Addmins('[some time literal]', [some integer]) from RDB$DATABASE;"
query (even using the same values that result in the error.
* 99.9% of the time, it works fine even under 2.1
* The error does not occur until after the function has completed, as
I receive FB_AddMins End in the debugger.
* I have also tried changing the isc_decode_timestamp and
isc_encode_timestamp to cdecl but it made no difference.
The exact error message is:
Statement failed, SQLCODE = -902
Unable to complete network request to host "lappy".
-Error reading data from the connection.
-An existing connection was forcibly closed by the remote host.
The function's purpose is to take a timestamp and a number of minutes,
and to return a timestamp that many minutes later. (Yes, I know this
particular function can also be done in PSQL). Can anyone see anything
glaringly wrong with the code?
TIA
Adam
(I have extracted the function into a new dll to simplify the required
code, but I have confirmed the problem still occurs with this separate
dll).
Declaration:
============
DECLARE EXTERNAL FUNCTION FB_ADDMINS
TIMESTAMP,INTEGER
RETURNS TIMESTAMP FREE_IT
ENTRY_POINT 'FB_AddMins' MODULE_NAME 'MyUDF';
UDF Code (Delphi 7):
==================
library MyUDF;
uses
SysUtils,
Classes,
uMyUDF in 'uMyUDF.pas';
{$R *.res}
exports
FB_AddMins;
begin
end.
---------------------------------------------
unit uMyUDF;
interface
type
Long = LongInt;
ULong = Cardinal;
ISC_TIMESTAMP = record
timestamp_date : Long;
timestamp_time : ULong;
end;
PISC_TIMESTAMP = ^ISC_TIMESTAMP;
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;
function FB_AddMins(var DT: ISC_TIMESTAMP; var Minutes: Integer):
PISC_TIMESTAMP; cdecl;
implementation
uses
ibexternals,
Windows,
DateUtils;
procedure isc_decode_timestamp(ib_date: PISC_TIMESTAMP; tm_date: PTM);
stdcall; external 'gds32.dll';
procedure isc_encode_timestamp(tm_date: PTM; ib_date: PISC_TIMESTAMP);
stdcall; external 'gds32.dll';
function TimeStampToDateTime(TimeStamp: ISC_TIMESTAMP): TDateTime;
var
TempTM: TM;
begin
isc_decode_timestamp(@TimeStamp,
@TempTM);
Result := EncodeDateTime(TempTM.tm_year+1900,
TempTM.tm_mon+1,
TempTM.tm_mday,
TempTM.tm_hour,
TempTM.tm_min,
0,
0);
end;
function DateTimeToTimeStamp(DateTime: TDateTime): ISC_TIMESTAMP;
var
Y,M,D,H,N,Dummy: Word;
TempTM: TM;
begin
DecodeDateTime(DateTime,
Y,
M,
D,
H,
N,
Dummy,
Dummy);
TempTM.tm_year := Y - 1900;
TempTM.tm_mon := M - 1;
TempTM.tm_mday := D;
TempTM.tm_hour := H;
TempTM.tm_min := N;
TempTM.tm_sec := 0;
isc_encode_timestamp(@TempTM, @Result);
end;
{Export Functions}
function FB_AddMins(var DT: ISC_TIMESTAMP; var Minutes: Integer):
PISC_TIMESTAMP; cdecl;
var
DTConverted: TDateTime;
begin
OutputDebugString('FB_AddMins Start');
DTConverted := TimeStampToDateTime(DT);
DTConverted := DTConverted + Minutes/1440;
DT := DateTimeToTimeStamp(DTConverted);
Result := @DT;
OutputDebugString('FB_AddMins End');
end;
end.
I am having some difficulty with a small number of UDF calls with
Firebird 2.1.
These have worked for years alongside Firebird 1.5. Furthermore, the
problem is intermittent and difficult to reduce to a simple test case,
as even removing an unrelated join from the query stops the error from
occurring. I do have a reproducable test case, but it involves a 30
line SQL statement and a 1GB database. I think it is better to rather
start with the code I am using to see if there are any obvious errors.
I have not been able to reproduce the error using "select
FB_Addmins('[some time literal]', [some integer]) from RDB$DATABASE;"
query (even using the same values that result in the error.
* 99.9% of the time, it works fine even under 2.1
* The error does not occur until after the function has completed, as
I receive FB_AddMins End in the debugger.
* I have also tried changing the isc_decode_timestamp and
isc_encode_timestamp to cdecl but it made no difference.
The exact error message is:
Statement failed, SQLCODE = -902
Unable to complete network request to host "lappy".
-Error reading data from the connection.
-An existing connection was forcibly closed by the remote host.
The function's purpose is to take a timestamp and a number of minutes,
and to return a timestamp that many minutes later. (Yes, I know this
particular function can also be done in PSQL). Can anyone see anything
glaringly wrong with the code?
TIA
Adam
(I have extracted the function into a new dll to simplify the required
code, but I have confirmed the problem still occurs with this separate
dll).
Declaration:
============
DECLARE EXTERNAL FUNCTION FB_ADDMINS
TIMESTAMP,INTEGER
RETURNS TIMESTAMP FREE_IT
ENTRY_POINT 'FB_AddMins' MODULE_NAME 'MyUDF';
UDF Code (Delphi 7):
==================
library MyUDF;
uses
SysUtils,
Classes,
uMyUDF in 'uMyUDF.pas';
{$R *.res}
exports
FB_AddMins;
begin
end.
---------------------------------------------
unit uMyUDF;
interface
type
Long = LongInt;
ULong = Cardinal;
ISC_TIMESTAMP = record
timestamp_date : Long;
timestamp_time : ULong;
end;
PISC_TIMESTAMP = ^ISC_TIMESTAMP;
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;
function FB_AddMins(var DT: ISC_TIMESTAMP; var Minutes: Integer):
PISC_TIMESTAMP; cdecl;
implementation
uses
ibexternals,
Windows,
DateUtils;
procedure isc_decode_timestamp(ib_date: PISC_TIMESTAMP; tm_date: PTM);
stdcall; external 'gds32.dll';
procedure isc_encode_timestamp(tm_date: PTM; ib_date: PISC_TIMESTAMP);
stdcall; external 'gds32.dll';
function TimeStampToDateTime(TimeStamp: ISC_TIMESTAMP): TDateTime;
var
TempTM: TM;
begin
isc_decode_timestamp(@TimeStamp,
@TempTM);
Result := EncodeDateTime(TempTM.tm_year+1900,
TempTM.tm_mon+1,
TempTM.tm_mday,
TempTM.tm_hour,
TempTM.tm_min,
0,
0);
end;
function DateTimeToTimeStamp(DateTime: TDateTime): ISC_TIMESTAMP;
var
Y,M,D,H,N,Dummy: Word;
TempTM: TM;
begin
DecodeDateTime(DateTime,
Y,
M,
D,
H,
N,
Dummy,
Dummy);
TempTM.tm_year := Y - 1900;
TempTM.tm_mon := M - 1;
TempTM.tm_mday := D;
TempTM.tm_hour := H;
TempTM.tm_min := N;
TempTM.tm_sec := 0;
isc_encode_timestamp(@TempTM, @Result);
end;
{Export Functions}
function FB_AddMins(var DT: ISC_TIMESTAMP; var Minutes: Integer):
PISC_TIMESTAMP; cdecl;
var
DTConverted: TDateTime;
begin
OutputDebugString('FB_AddMins Start');
DTConverted := TimeStampToDateTime(DT);
DTConverted := DTConverted + Minutes/1440;
DT := DateTimeToTimeStamp(DTConverted);
Result := @DT;
OutputDebugString('FB_AddMins End');
end;
end.