Delphi Interface
This chapter describes functions used by Delphi interface with examples.fName used to receive a message
1. Overview
A Delphi interface is a strong alternative to Visual Basic. It includes interface modules used to call the functions provided by client library. All functions are available by installing an interface module. Unlike Power Builder or Visual Basic, Delphi supports the concept of a pointer and passes a value in the same way as C language. In addition, Delphi uses the Pascal syntax so that those who are familiar with existing languages can easily use Delphi. Therefore, additional macro or component is not needed to use Delphi.
The followings are the components of Delphi interface.
| Module | Description |
|---|---|
atmi.pas |
File that defines a prototype for atmi functions. |
fdl.pas |
File that defines a prototype for field key functions |
|
For detailed information about the prototypes and functions of atmi and field key functions, refer to Tmax Reference Guide and Tmax Application Development Guide. The usage of Delphi interface will be explained in the example programs. |
2. Example Program
The programs retrieve the name and department of an employee from Oracle database when the employee number is entered.
2.1. Program Configuration
Add Atmi.pas, fdl.pas, TuxSvc.pas as a module in project.
-
Common programs
Program file Description demo.f
File that defines a field key buffer.
tmax
Library file.
-
Client programs
Program file Description Atmi.dcu
Object file created by compiling an atmi source file.
Atmi.pas
File that defines a prototype for atmi functions.
EmployeeMgr.bpg
Project group file.
EmployeeMgr.cfg
Project environment configuration file.
EmployeeMgr.dof
Delphi option file.
EmployeeMgr.dpr
Project file that has multiple pas files and dfm files.
EmployeeMgr.exe
Executable object file.
EmployeeMgr.res
Compiled binary resource file.
Fdl.dcu
Object file created by compiling an Fdl source file.
Fdl.pas
File that defines a prototype for field key functions.
TuxSvc.pas
Tuxedo convertible source file.
main.dcu
Object file created by compiling a main source file.
main.dfm
Main form file.
main.pas
Client program.
-
Server programs
Program file Description emp_c.mk
Makefile.
emp_c.pc
Server program. AIX and Oracle 9i are used.
employee.m
Tmax environment configuration file.
2.2. Program Features
-
Client programs
Function Description Tmax connection
A Tmax user account, and a user name for application definition are used as an argument.
Buffer type
An 'fdl' file needs to be created by compiling a field key buffer and a field key file using the fdlc utility.
Communication mode
Synchrnomous communication using tpcall(). A send buffer and a receive buffer are the same.
Transaction option
TMS allocates AutoTransaction.
-
Server programs
Function Description Service
FDLSELECT, FDLDELETE, FDLUPDATE, and FDLINSERT need to be created.
Database
Oracle database. Database information is specified in SVRGROUP of a system configuration file.
2.3. Common Programs
DataBase EMP Table
The following is an example of a basic table used for operating a DB.
EMPNO NUMBER NOT NULL P1 ENAME VARCHAR(16) JOB VARCHAR(16) MGR NUMBER HIREDATE DATE SAL NUMBER(7,2) COMM NUMBER(7,2) DEPTNO NUMBER
Field Key Buffer Definition
The following example defines a field key buffer.
<demo.f>
#For tmax demo employee program EMPNO 7500 long - - ENAME 7501 string - - JOB 7502 string - - MGR 7503 long - - DATE 7504 string - - SAL 7505 float - - COMM 7506 float - - DEPTNO 7507 long - - E_TYPE 9009 long - - E_CODE 9010 long - - E_MSG 9011 string - - E_TMP 9012 long - -
Tmax Environment Configuration
The following shows an example of Tmax environment configuration file.
<tmconfig.m>
*DOMAIN
dom1 SHMKEY = 70000, MAXUSER = 200, MINCLH = 1, MAXCLH = 5,
TPORTNO = 8888, BLOCKTIME = 200, TXTIME = 200
*NODE
tmax1 TMAXDIR = "/home/tmax",
APPDIR = "/home/tmax/appbin",
PATHDIR = "/home/tmax/path",
TLOGDIR = "/home/tmax/log/tlog",
SLOGDIR = "/home/tmax/log/slog"
ULOGDIR = "/home/tmax/log/ulog"
*SVRGROUP
svg1 NODENAME = tmax1, DBNAME = ORACLE,
OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60",
TMSNAME = svg1_tms
*SERVER
emp_c SVGNAME = svg1, MIN = 1
*SERVICE
FDLSELECT SVRNAME = emp_c
FDLUPDATE SVRNAME = emp_c
FDLDELETE SVRNAME = emp_c
FDLINSERT SVRNAME = emp_c
2.4. Client Programs
Main Screen Format Design
The following shows a main screen format.

The following table shows the components of a main screen format.
| Control name | Control type | Note |
|---|---|---|
EmployeeMgrForm |
Form |
Caption="Employee management program" |
LabelErr |
TLabel |
Caption="Error" |
BtnExit |
TButton |
Caption="Close" |
BtnIns |
TButton |
Caption="Insert" |
BtnDel |
TButton |
Caption="Delete" |
BtnUdt |
TButton |
Caption="Update" |
BtnSel |
TButton |
Caption="Query" |
EditName |
TEdit |
|
EditEmpNo |
TEdit |
|
EditDept |
TEdit |
|
EditComm |
TEdit |
|
EditSal |
TEdit |
|
EditDate |
TEdit |
|
EditMgr |
TEdit |
|
EditJob |
TEdit |
|
MList |
TEdit |
|
BtnReturn |
TEdit |
The following example executes a designed main screen format.
<main.pas>
unit main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TEmployeeMgrForm = class(TForm)
LabelEmpNo: TLabel;
LabelName: TLabel;
EditEmpNo: TEdit;
EditName: TEdit;
GroupBoxInfo: TGroupBox;
LabelJob: TLabel;
LabelMgr: TLabel;
LabelDate: TLabel;
LabelSal: TLabel;
EditJob: TEdit;
EditMgr: TEdit;
EditDate: TEdit;
EditSal: TEdit;
EditComm: TEdit;
EditDept: TEdit;
LabelComm: TLabel;
LabelDept: TLabel;
BtnSel: TButton;
BtnUdt: TButton;
BtnDel: TButton;
BtnIns: TButton;
BtnExit: TButton;
LabelErr: TLabel;
MList: TMemo;
BtnReturn: TButton;
procedure BtnExitClick(Sender: TObject);
procedure BtnSelClick(Sender: TObject);
procedure BtnUdtClick(Sender: TObject);
procedure BtnDelClick(Sender: TObject);
procedure BtnInsClick(Sender: TObject);
procedure tmaxStart();
procedure BtnReturnClick(Sender: TObject);
procedure ViewErr(a:Pointer);
{ Private declarations }
public
{ Public declarations }
end;
var
EmployeeMgrForm: TEmployeeMgrForm;
implementation
// Use Atmi and Fdl
uses Atmi, Fdl;
const BufferSize = 1024;
{$R *.DFM}
// The length of a string is omitted.{$H+}
{$H+}
procedure TEmployeeMgrForm.tmaxStart();
var
tpinfo: pTPSTART;
ret: integer;
begin
// Defined in the atmi.pas file.
// Function tmaxreadenv(a:PChar; b:PChar):Integer; cdecl; external TmaxDLL;
// For the detailed information, refer to Tmax Reference Guide.
ret := tmaxreadenv('C:\tmax.env', 'aix5l389');
if ret < 0 then begin
ShowMessage('tmaxreadenv Error');
Exit;
end;
// Allocate a buffer to send user information for tpstart.
tpinfo := tpalloc('TPSTART', NIL, 0);
if tpinfo = Nil then begin
ShowMessage('tpinfo tpalloc failed,' + StrPas(tpstrerror(gettperrno)));
tpfree(tpinfo);
Exit;
end;
//
// The following options can be specified.
//
// User account for authentication
// tpinfo.usrname := 'tmax';
// Name used to receive a message voluntarily
// tpinfo.cltname := 'tmax';
// Allow to accept a message voluntarily
// tpinfo.flags := TPUNSOL_POLL;
// Tmax connection
ret := tpstart(tpinfo);
if ret < 0 then begin
ShowMessage('tpstart failed' + StrPas(tpstrerror(gettperrno)));
tpfree(tpinfo);
tpend();
Exit;
end;
// Free the buffer used to send user information
tpfree(tpinfo);
end;
// When the Close button is clicked.
procedure TEmployeeMgrForm.BtnExitClick(Sender: TObject);
begin
tpend();
close;
end;
procedure TEmployeeMgrForm.BtnUdtClick(Sender: TObject);
var sndbuf, revbuf: Pointer;
ret, empno_l, mgr_l, deptno_l: longint;
sal_f, comm_f: single;
job_s, ename_s: pointer;
rlen: integer;
date_s: string[100];
begin
tmaxStart();
// Allocate a buffer to send
sndbuf := fballoc(1000, 10000);
if sndbuf = Nil then begin
ShowMessage('sndbuf tpalloc failed, ' + StrPas(tpstrerror(gettperrno)));
fbfree(sndbuf);
tpend();
Exit;
end;
// Allocate a buffer to receive
revbuf := fballoc(1000, 10000);
if revbuf = Nil then begin
ShowMessage('revbuf tpalloc failed, ' + StrPas(tpstrerror(gettperrno)));
fbfree(revbuf);
tpend();
Exit;
end;
empno_l := StrToInt(EditEmpNo.text);
fbput(sndbuf, fbget_fldkey('EMPNO'), @empno_l, 0);
ename_s := PChar(EditName.text);
fbput(sndbuf, fbget_fldkey('ENAME'), ename_s, 0);
job_s := PChar(EditJob.text);
fbput(sndbuf, fbget_fldkey('JOB'), job_s, 0);
mgr_l := StrToInt(EditMgr.text);
fbput(sndbuf, fbget_fldkey('MGR'), @mgr_l, 0);
// date_s := PChar(EditDate.text);
// fbput(sndbuf, fbget_fldkey('DATE'), @date_s, 0);
date_s := EditDate.text;
rlen := length(EditDate.text);
ret := fbchg_tu(sndbuf, fbget_fldkey('DATE'),0 ,@date_s[1], 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'DATE error!!!';
Exit;
end;
sal_f := StrToFloat(EditSal.text);
fbput(sndbuf, fbget_fldkey('SAL'), @sal_f, 0);
comm_f := StrToFloat(EditComm.text);
fbput(sndbuf, fbget_fldkey('COMM'), @comm_f, 0);
deptno_l := StrToInt(EditDept.text);
fbput(sndbuf, fbget_fldkey('DEPTNO'), @deptno_l, 0);
// Begin a transaction
ret := tx_begin();
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'tx_begin error';
Exit;
end;
// Initiate a service
ret := tpcall('FDLUPDATE', sndbuf, 0, @revbuf, @rlen, 0);
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
ret := tx_commit();
if ret < 0 then begin
ShowMessage('tx_commit failed! ' + StrPas(tpstrerror(gettperrno)));
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
// Free the allocated buffer
fbfree(sndbuf);
fbfree(revbuf);
tpend();
end;
procedure TEmployeeMgrForm.BtnDelClick(Sender: TObject);
var sndbuf, revbuf: Pointer;
empno_l, ret: longint;
rlen: integer;
begin
tmaxStart();
// Allocate a buffer to send data to the server
sndbuf := fballoc(1000, 10000);
if sndbuf = Nil then begin
ShowMessage('sndbuf tpalloc failed, ' + StrPas(tpstrerror(gettperrno)));
tpend();
Exit;
end;
// Allocate a buffer to receive data from the server
revbuf := fballoc(1000, 10000);
if sndbuf = Nil then begin
ShowMessage('sndbuf tpalloc failed, ' + StrPas(tpstrerror(gettperrno)));
tpend();
Exit;
end;
empno_l := StrToInt(EditEmpNo.text);
fbput(sndbuf, fbget_fldkey('EMPNO'), @empno_l, 0);
// Begin a transaction
ret := tx_begin();
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'tx_begin error';
Exit;
end;
// Send a service request to the server
ret := tpcall('FDLDELETE', sndbuf, 0, @revbuf, @rlen, 0);
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
ret := tx_commit();
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
// Free the allocated buffer
fbfree(sndbuf);
fbfree(revbuf);
tpend();
end;
procedure TEmployeeMgrForm.BtnInsClick(Sender: TObject);
var sndbuf, revbuf: Pointer;
empno_l, mgr_l, deptno_l: longint;
sal_f, comm_f: single;
job_s, ename_s, date_s: string[100];
ret, rlen: integer;
begin
// Function to call tpstart
tmaxStart();
// Allocate a buffer to send
LabelErr.Caption := '';
sndbuf := fballoc(1000,10000);
if sndbuf = Nil then begin
LabelErr.Caption := 'sndbuf tpalloc failed, '
+ StrPas(tpstrerror(gettperrno));
fbfree(sndbuf);
tpend();
Exit;
end;
revbuf := fballoc(100,1000);
if revbuf = Nil then begin
LabelErr.Caption := 'revbuf tpalloc failed, '
+ StrPas(tpstrerror(gettperrno));
fbfree(revbuf);
tpend();
Exit;
end;
empno_l := StrToInt(EditEmpNo.text);
ret := fbput(sndbuf, fbget_fldkey('EMPNO'), @empno_l, 0);
if ret = -1 then begin
LabelErr.Caption := 'EMPNO error!!!';
Exit;
end;
ename_s := EditName.text;
rlen := length(EditName.text);
ret := fbchg_tu(sndbuf, fbget_fldkey('ENAME'),0 ,@ename_s[1], 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'ENAME error!!!';
Exit;
end;
job_s := EditJob.text;
rlen := length(EditJob.text);
ret := fbchg_tu(sndbuf, fbget_fldkey('JOB'),0 ,@job_s[1], 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'JOB error!!!';
Exit;
end;
mgr_l := StrToInt(EditMgr.text);
ret := fbput(sndbuf, fbget_fldkey('MGR'), @mgr_l, 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'MGR error!!!';
Exit;
end;
date_s := EditDate.text;
rlen := length(EditDate.text);
ret := fbchg_tu(sndbuf, fbget_fldkey('DATE'),0 ,@date_s[1], 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'DATE error!!!';
Exit;
end;
sal_f := StrToFloat(EditSal.text);
ret := fbput(sndbuf, fbget_fldkey('SAL'), @sal_f, 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'SAL error!!!';
Exit;
end;
comm_f := StrToFloat(EditComm.text);
ret := fbput(sndbuf, fbget_fldkey('COMM'), @comm_f, 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'COMM error!!!';
Exit;
end;
deptno_l := StrToInt(EditDept.text);
ret := fbput(sndbuf, fbget_fldkey('DEPTNO'), @deptno_l, 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'DEPTNO error!!!';
Exit;
end;
// Begin a transaction
ret := tx_begin();
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'tx_begin error';
Exit;
end;
// Initiate a service
ret := tpcall('FDLINSERT', sndbuf, 0, @revbuf, @rlen, 0);
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
ret := tx_commit();
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
// Free a buffer to send data
fbfree(revbuf);
fbfree(sndbuf);
tpend();
end;
procedure TEmployeeMgrForm.BtnReturnClick(Sender: TObject);
begin
BtnReturn.Visible := false;
MList.Visible := false;
end;
procedure TEmployeeMgrForm.ViewErr( a:Pointer );
var typeS: PChar;
codeS: PChar;
msgS: PChar;
tmpS: PChar;
// Iret: Integer;
begin
// E_TYPE 9009 long - -
// E_CODE 9010 long - -
// E_MSG 9011 string - -
// E_TMP 9012 long - -
typeS := fbgetvals(a, fbget_fldkey('E_TYPE'), 0);
codeS := fbgetvals(a, fbget_fldkey('E_CODE'), 0);
msgS := fbgetvals(a, fbget_fldkey('E_MSG'), 0);
tmpS := fbgetvals(a, fbget_fldkey('E_TMP'), 0);
ShowMessage('Error Type : ' + typeS + ' ,Code : ' + codeS + ' ,Message :
' + msgS + ' ,Tmp : ' + tmpS);
end;
Inquiry Screen
The following figure shows an inquiry screen format.

The following example executes a designed inquiry screen format.
unit main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TEmployeeMgrForm = class(TForm)
LabelEmpNo: TLabel;
LabelName: TLabel;
EditEmpNo: TEdit;
EditName: TEdit;
GroupBoxInfo: TGroupBox;
LabelJob: TLabel;
LabelMgr: TLabel;
LabelDate: TLabel;
LabelSal: TLabel;
EditJob: TEdit;
EditMgr: TEdit;
EditDate: TEdit;
EditSal: TEdit;
EditComm: TEdit;
EditDept: TEdit;
LabelComm: TLabel;
LabelDept: TLabel;
BtnSel: TButton;
BtnUdt: TButton;
BtnDel: TButton;
BtnIns: TButton;
BtnExit: TButton;
LabelErr: TLabel;
MList: TMemo;
BtnReturn: TButton;
procedure BtnExitClick(Sender: TObject);
procedure BtnSelClick(Sender: TObject);
procedure BtnUdtClick(Sender: TObject);
procedure BtnDelClick(Sender: TObject);
procedure BtnInsClick(Sender: TObject);
procedure tmaxStart();
procedure BtnReturnClick(Sender: TObject);
procedure ViewErr( a:Pointer );
{ Private declarations }
public
{ Public declarations }
end;
var
EmployeeMgrForm: TEmployeeMgrForm;
implementation
// Use Atmi and Fdl.
uses Atmi, Fdl;
const BufferSize = 1024;
{$R *.DFM}
// The value of a string is omitted.
{$H+}
procedure TEmployeeMgrForm.tmaxStart();
var
tpinfo: pTPSTART;
ret: integer;
begin
// Defined in the atmi.pas file.
// Function tmaxreadenv(a:PChar; b:PChar):Integer; cdecl; external TmaxDLL;
// For the detailed information, refer to Tmax Reference Guide.
ret := tmaxreadenv('C:\tmax.env', 'aix5l389');
if ret < 0 then begin
ShowMessage('tmaxreadenv Error');
Exit;
end;
// Send a buffer used to send user information for tpstart.
tpinfo := tpalloc('TPSTART', NIL, 0);
if tpinfo = Nil then begin
ShowMessage('tpinfo tpalloc failed,' + StrPas(tpstrerror(gettperrno)));
tpfree(tpinfo);
Exit;
end;
//
// The following options can be specified.
//
// User account for authentication
// tpinfo.usrname := 'tmax';
// Name used to receive a message voluntarily
// tpinfo.cltname := 'tmax';
// Allow to accept a message voluntarily
// tpinfo.flags := TPUNSOL_POLL;
// Tmax connection
ret := tpstart(tpinfo);
if ret < 0 then begin
ShowMessage('tpstart failed' + StrPas(tpstrerror(gettperrno)));
tpfree(tpinfo);
tpend();
Exit;
end;
// Free the buffer used to send user information
tpfree(tpinfo);
end;
// When the Close button is clicked.
procedure TEmployeeMgrForm.BtnExitClick(Sender: TObject);
begin
tpend();
close;
end;
procedure TEmployeeMgrForm.BtnUdtClick(Sender: TObject);
var sndbuf, revbuf: Pointer;
ret, empno_l, mgr_l, deptno_l: longint;
sal_f, comm_f: single;
job_s, ename_s: pointer;
rlen: integer;
date_s: string[100];
begin
tmaxStart();
// Allocate a buffer to send
sndbuf := fballoc(1000, 10000);
if sndbuf = Nil then begin
ShowMessage('sndbuf tpalloc failed, ' + StrPas(tpstrerror(gettperrno)));
fbfree(sndbuf);
tpend();
Exit;
end;
// Allocate a buffer to receive
revbuf := fballoc(1000, 10000);
if revbuf = Nil then begin
ShowMessage('revbuf tpalloc failed, ' + StrPas(tpstrerror(gettperrno)));
fbfree(revbuf);
tpend();
Exit;
end;
empno_l := StrToInt(EditEmpNo.text);
fbput(sndbuf, fbget_fldkey('EMPNO'), @empno_l, 0);
ename_s := PChar(EditName.text);
fbput(sndbuf, fbget_fldkey('ENAME'), ename_s, 0);
job_s := PChar(EditJob.text);
fbput(sndbuf, fbget_fldkey('JOB'), job_s, 0);
mgr_l := StrToInt(EditMgr.text);
fbput(sndbuf, fbget_fldkey('MGR'), @mgr_l, 0);
// date_s := PChar(EditDate.text);
// fbput(sndbuf, fbget_fldkey('DATE'), @date_s, 0);
date_s := EditDate.text;
rlen := length(EditDate.text);
ret := fbchg_tu(sndbuf, fbget_fldkey('DATE'),0 ,@date_s[1], 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'DATE error!!!';
Exit;
end;
sal_f := StrToFloat(EditSal.text);
fbput(sndbuf, fbget_fldkey('SAL'), @sal_f, 0);
comm_f := StrToFloat(EditComm.text);
fbput(sndbuf, fbget_fldkey('COMM'), @comm_f, 0);
deptno_l := StrToInt(EditDept.text);
fbput(sndbuf, fbget_fldkey('DEPTNO'), @deptno_l, 0);
// Begin a transaction
ret := tx_begin();
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'tx_begin error';
Exit;
end;
// Initiate a service
ret := tpcall('FDLUPDATE', sndbuf, 0, @revbuf, @rlen, 0);
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
ret := tx_commit();
if ret < 0 then begin
ShowMessage('tx_commit failed! ' + StrPas(tpstrerror(gettperrno)));
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
// Free the allocated buffer
fbfree(sndbuf);
fbfree(revbuf);
tpend();
end;
procedure TEmployeeMgrForm.BtnDelClick(Sender: TObject);
var sndbuf, revbuf: Pointer;
empno_l, ret: longint;
rlen: integer;
begin
tmaxStart();
// Allocate a buffer to send data to the server
sndbuf := fballoc(1000, 10000);
if sndbuf = Nil then begin
ShowMessage('sndbuf tpalloc failed, ' + StrPas(tpstrerror(gettperrno)));
tpend();
Exit;
end;
// Allocate a buffer to receive data from the server
revbuf := fballoc(1000, 10000);
if sndbuf = Nil then begin
ShowMessage('sndbuf tpalloc failed, ' + StrPas(tpstrerror(gettperrno)));
tpend();
Exit;
end;
empno_l := StrToInt(EditEmpNo.text);
fbput(sndbuf, fbget_fldkey('EMPNO'), @empno_l, 0);
// Begin a transaction
ret := tx_begin();
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'tx_begin error';
Exit;
end;
// Send a service request to the server
ret := tpcall('FDLDELETE', sndbuf, 0, @revbuf, @rlen, 0);
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
ret := tx_commit();
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
// Free the allocated buffer
fbfree(sndbuf);
fbfree(revbuf);
tpend();
end;
procedure TEmployeeMgrForm.BtnInsClick(Sender: TObject);
var sndbuf, revbuf: Pointer;
empno_l, mgr_l, deptno_l: longint;
sal_f, comm_f: single;
job_s, ename_s, date_s: string[100];
ret, rlen: integer;
begin
// Function to call tpstart
tmaxStart();
// Allocate a buffer to send
LabelErr.Caption := '';
sndbuf := fballoc(1000,10000);
if sndbuf = Nil then begin
LabelErr.Caption := 'sndbuf tpalloc failed, '
+ StrPas(tpstrerror(gettperrno));
fbfree(sndbuf);
tpend();
Exit;
end;
revbuf := fballoc(100,1000);
if revbuf = Nil then begin
LabelErr.Caption := 'revbuf tpalloc failed, '
+ StrPas(tpstrerror(gettperrno));
fbfree(revbuf);
tpend();
Exit;
end;
empno_l := StrToInt(EditEmpNo.text);
ret := fbput(sndbuf, fbget_fldkey('EMPNO'), @empno_l, 0);
if ret = -1 then begin
LabelErr.Caption := 'EMPNO error!!!';
Exit;
end;
ename_s := EditName.text;
rlen := length(EditName.text);
ret := fbchg_tu(sndbuf, fbget_fldkey('ENAME'),0 ,@ename_s[1], 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'ENAME error!!!';
Exit;
end;
job_s := EditJob.text;
rlen := length(EditJob.text);
ret := fbchg_tu(sndbuf, fbget_fldkey('JOB'),0 ,@job_s[1], 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'JOB error!!!';
Exit;
end;
mgr_l := StrToInt(EditMgr.text);
ret := fbput(sndbuf, fbget_fldkey('MGR'), @mgr_l, 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'MGR error!!!';
Exit;
end;
date_s := EditDate.text;
rlen := length(EditDate.text);
ret := fbchg_tu(sndbuf, fbget_fldkey('DATE'),0 ,@date_s[1], 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'DATE error!!!';
Exit;
end;
sal_f := StrToFloat(EditSal.text);
ret := fbput(sndbuf, fbget_fldkey('SAL'), @sal_f, 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'SAL error!!!';
Exit;
end;
comm_f := StrToFloat(EditComm.text);
ret := fbput(sndbuf, fbget_fldkey('COMM'), @comm_f, 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'COMM error!!!';
Exit;
end;
deptno_l := StrToInt(EditDept.text);
ret := fbput(sndbuf, fbget_fldkey('DEPTNO'), @deptno_l, 0);
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'DEPTNO error!!!';
Exit;
end;
// Begin a transaction
ret := tx_begin();
if ret = -1 then begin
LabelErr.Caption := LabelErr.Caption + 'tx_begin error';
Exit;
end;
// Initiate a service
ret := tpcall('FDLINSERT', sndbuf, 0, @revbuf, @rlen, 0);
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
ret := tx_commit();
if ret < 0 then begin
ViewErr(revbuf);
tx_rollback();
fbfree(sndbuf);
fbfree(revbuf);
tpend();
Exit;
end;
// Free the allocated buffer
fbfree(revbuf);
fbfree(sndbuf);
tpend();
end;
procedure TEmployeeMgrForm.BtnReturnClick(Sender: TObject);
begin
BtnReturn.Visible := false;
MList.Visible := false;
end;
procedure TEmployeeMgrForm.ViewErr( a:Pointer );
var typeS: PChar;
codeS: PChar;
msgS: PChar;
tmpS: PChar;
// Iret: Integer;
begin
// E_TYPE 9009 long - -
// E_CODE 9010 long - -
// E_MSG 9011 string - -
// E_TMP 9012 long - -
typeS := fbgetvals(a, fbget_fldkey('E_TYPE'), 0);
codeS := fbgetvals(a, fbget_fldkey('E_CODE'), 0);
msgS := fbgetvals(a, fbget_fldkey('E_MSG'), 0);
tmpS := fbgetvals(a, fbget_fldkey('E_TMP'), 0);
ShowMessage('Error Type : ' + typeS + ' ,Code : ' + codeS + ' ,Message : '
+ msgS + ' ,Tmp : ' + tmpS);
end;
Oracle Error Display
The following figure is an Oracle error message display screen.

The following example executes an Oracle error display screen.
procedure TEmployeeMgrForm.ViewErr( a:Pointer );
var typeS: PChar;
codeS: PChar;
msgS: PChar;
tmpS: PChar;
// Iret: Integer;
begin
// E_TYPE 9009 long - -
// E_CODE 9010 long - -
// E_MSG 9011 string - -
// E_TMP 9012 long - -
typeS := fbgetvals(a, fbget_fldkey('E_TYPE'), 0);
codeS := fbgetvals(a, fbget_fldkey('E_CODE'), 0);
msgS := fbgetvals(a, fbget_fldkey('E_MSG'), 0);
tmpS := fbgetvals(a, fbget_fldkey('E_TMP'), 0);
ShowMessage('Error Type : ' + typeS + ' ,Code : ' + codeS + ' ,Message :
' + msgS + ' ,Tmp : ' + tmpS);
end;
2.5. Server Programs
Service Programs
The following is an example of service program.
<em4p_c.pc>
#include <stdio.h>
#include <ctype.h>
#include <tuxinc/macro.h>
#include "../../fdl/demo_fdl.h"
EXEC SQL include sqlca.h;
EXEC SQL INCLUDE ORACA;
EXEC ORACLE OPTION (ORACA=YES);
EXEC ORACLE OPTION (RELEASE_CURSOR=YES);
#define INP 1
#define ORA 2
#define TMX 3
#define APP 4
EXEC SQL begin declare section;
int h_empno;
char h_ename[11];
char h_job[10];
int h_mgr;
char h_date[11];
float h_sal;
float h_comm;
int h_deptno;
EXEC SQL end declare section;
void svc_error(long type, long err_code, char *msg, long tmp);
FDLINSERT( TPSVCINFO *msg )
{
FBUF *rcvbuf;
int i, occurrence;
rcvbuf = (FBUF *)msg->data;
h_empno = h_mgr = h_sal = h_comm = h_deptno = 0;
memset( h_ename, 0x00, sizeof( h_ename ) );
memset( h_job, 0x00, sizeof( h_job ) );
memset( h_date, 0x00, sizeof( h_date ) );
occurrence = fbkeyoccur(rcvbuf, EMPNO);
for (i=0; i< occurrence; i++){
fbget_tu ( rcvbuf, EMPNO, i, (char *)&h_empno, 0 );
fbget_tu ( rcvbuf, MGR, i, (char *)&h_mgr, 0 );
fbget_tu ( rcvbuf, SAL, i, (char *)&h_sal, 0 );
fbget_tu ( rcvbuf, COMM, i, (char *)&h_comm, 0 );
fbget_tu ( rcvbuf, DEPTNO,i, (char *)&h_deptno, 0 );
fbget_tu ( rcvbuf, ENAME, i, (char *)h_ename, 0 );
fbget_tu ( rcvbuf, JOB , i, (char *)h_job, 0 );
fbget_tu ( rcvbuf, DATE , i, (char *)h_date, 0 );
EXEC SQL INSERT
INTO emp(empno, ename, job, mgr, hiredate, sal,comm, deptno)
VALUES (:h_empno, :h_ename, :h_job, :h_mgr,
to_date(:h_date,'yyyymmdd'), :h_sal, :h_comm, :h_deptno );
}
if(sqlca.sqlcode != 0)
goto LB_DBERROR;
EXEC SQL WHENEVER SQLERROR
goto LB_DBERROR;
tpreturn(TPSUCCESS, 0L, (char *)rcvbuf, 0L, 0L);
LB_DBERROR :
EXEC SQL WHENEVER SQLERROR CONTINUE;
svc_error(ORA, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, 0);
}
FDLDELETE( TPSVCINFO *msg )
{
FBUF *rcvbuf;
int i, occurrence;
rcvbuf = ( FBUF *)msg->data;
occurrence = fbkeyoccur(rcvbuf, EMPNO);
for (i=0; i< occurrence; i++){
fbget_tu (rcvbuf, EMPNO, i, (char *)&h_empno , 0);
EXEC SQL DELETE
FROM emp
WHERE empno = :h_empno;
}
if(sqlca.sqlcode != 0)
goto LB_DBERROR;
EXEC SQL WHENEVER SQLERROR
goto LB_DBERROR ;
EXEC SQL WHENEVER NOT FOUND
goto LB_DBERROR ;
tpreturn(TPSUCCESS, 0L, (char *)rcvbuf, 0L, 0L);
LB_DBERROR :
EXEC SQL WHENEVER SQLERROR CONTINUE;
svc_error(ORA, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, 0) ;
}
FDLSELECT( TPSVCINFO *msg )
{
FBUF *rcvbuf;
FLDLEN fldlen;
int i=0, ROWMEM=200, CHKROW=500;
rcvbuf = (FBUF *)msg->data;
if((rcvbuf=(FBUF *)tprealloc((char *)rcvbuf,ROWMEM*CHKROW))==NULL){
rcvbuf=(FBUF *)msg->data;
goto LB_TMAXERROR ;
}
h_empno = h_mgr = h_sal = h_comm = h_deptno = 0;
memset( h_ename, 0x00, sizeof( h_ename ) );
memset( h_job, 0x00, sizeof( h_job ) );
memset( h_date, 0x00, sizeof( h_date ) );
fbget_tu( rcvbuf, EMPNO, 0, (char *)&h_empno, &fldlen);
EXEC SQL DECLARE DB_CUR CURSOR FOR
SELECT nvl(empno,0), nvl(ename,' '), nvl(job,' '),
nvl(to_char(hiredate,'yyyymmdd'),' '), nvl(mgr,0),
nvl(sal,0), nvl(comm,0), nvl(deptno,0)
FROM emp
WHERE empno >= :h_empno-50 AND empno <= :h_empno+50;
EXEC SQL OPEN DB_CUR;
if(sqlca.sqlcode != 0)
goto LB_DBERROR;
EXEC SQL WHENEVER SQLERROR
goto LB_DBERROR ;
EXEC SQL WHENEVER NOT FOUND
Do break ;
while(1) {
EXEC SQL FETCH DB_CUR
INTO :h_empno,
:h_ename,
:h_job,
:h_date,
:h_mgr,
:h_sal,
:h_comm,
:h_deptno;
fbchg_tu(rcvbuf, EMPNO, i,(char *)&h_empno, 0);
fbchg_tu(rcvbuf, MGR, i ,(char *)&h_mgr, 0);
fbchg_tu(rcvbuf, SAL, i ,(char *)&h_sal, 0);
fbchg_tu(rcvbuf, DEPTNO, i,(char *)&h_deptno, 0);
fbchg_tu(rcvbuf, COMM, i,(char *)&h_comm, 0);
fbchg_tu(rcvbuf, ENAME, i,(char *)h_ename, 0);
fbchg_tu(rcvbuf, JOB, i,(char *)h_job, 0);
fbchg_tu(rcvbuf, DATE, i,(char *)h_date, 0);
i++;
}
if (i < 1)
goto LB_DBERROR;
EXEC SQL CLOSE DB_CUR;
tpreturn(TPSUCCESS, 0L, (char *)rcvbuf, 0L, 0L);
LB_DBERROR :
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL CLOSE DB_CUR ;
svc_error(ORA, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, 0L);
LB_TMAXERROR :
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL CLOSE DB_CUR ;
svc_error(TMX, tperrno, "", 0L) ;
}
FDLUPDATE( TPSVCINFO *msg )
{
FBUF *rcvbuf ;
int i, occurrence;
rcvbuf = (FBUF *)msg->data;
h_empno = h_mgr = h_sal = h_comm = h_deptno = 0;
memset( h_ename, 0x00, sizeof( h_ename ) );
memset( h_job, 0x00, sizeof( h_job ) );
memset( h_date, 0x00, sizeof( h_date ) );
occurrence = fbkeyoccur(rcvbuf, EMPNO);
for (i=0; i< occurrence; i++){
fbget_tu ( rcvbuf, EMPNO, i, (char *)&h_empno, 0);
fbget_tu ( rcvbuf, ENAME, i, (char *)h_ename, 0);
fbget_tu ( rcvbuf, JOB, i, (char *)h_job, 0);
fbget_tu ( rcvbuf, MGR, i, (char *)&h_mgr, 0);
fbget_tu ( rcvbuf, SAL, i, (char *)&h_sal, 0);
fbget_tu ( rcvbuf, COMM, i, (char *)&h_comm,0);
fbget_tu ( rcvbuf, DEPTNO, i, (char *)&h_deptno,0);
fbget_tu ( rcvbuf, DATE , i, (char *)h_date, 0 );
EXEC SQL UPDATE emp
SET ename = nvl(:h_ename, ename),
job = nvl(:h_job, job),
mgr = :h_mgr,
hiredate = nvl(to_date(:h_date,'yyyymmdd'),hiredate),
sal = :h_sal,
comm = :h_comm,
deptno = :h_deptno
WHERE empno = :h_empno;
if(sqlca.sqlcode != 0)
goto LB_DBERROR;
EXEC SQL WHENEVER SQLERROR
goto LB_DBERROR;
EXEC SQL WHENEVER NOT FOUND
goto LB_DBERROR;
}
tpreturn(TPSUCCESS, 0L, (char *)rcvbuf, 0L, 0L);
LB_DBERROR :
EXEC SQL WHENEVER SQLERROR CONTINUE;
svc_error(ORA, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, 0L);
}
/*********************************************************************
* Error Processing: If an error occurs in a service routine, the error is entered to the buffer and sent to the client.
********************************************************************/
void svc_error(long type, long err_code, char *msg, long tmp) {
FBUF *transf;
char *svcname;
char err_msg[100];
char temp[100];
int i = 0;
printf("type ==>[%ld]\n", type);
printf("err_code ==>[%ld]\n", err_code);
printf("msg ==>[%s]\n", msg);
strcpy(err_msg, msg);
if ((transf = (FBFR *)tpalloc("FML", NULL, 0)) == NULL) {
printf("tpalloc failed! errno = %d\n", tperrno);
}
switch(type) {
case INP:
switch(err_code) {
case -1000:
strcpy(err_msg, "The user has no privilege.");
break;
default:
strcpy(err_msg,
"An input error message has not been registered.");
}
break;
case ORA:
if (strlen(err_msg)== 0)
strcpy(err_msg, sqlca.sqlerrm.sqlerrmc);
break;
case TMX:
if (strlen(err_msg)== 0)
strcpy(err_msg, tpstrerror(tperrno));
break;
case APP:
if (strlen(err_msg)== 0) {
/* Sets an error message if * err_mssg="" is specified. ******/
switch(err_code) {
case -500: /* SYSTEM Error */
strcpy(err_msg,"File creation error.");
break;
case -502:
strcpy(err_msg,"Failed to call an internal service.");
break;
case -504:
strcpy(err_msg, "Socket communication error.");
break;
case -505: /* Displays 'processing error if the application is updated by another transaction.*/
/* [%s] has been updated by another application after an inquiry is performed.
\n\nQuery again and process it.": Processed in a client*/
strcpy(err_msg, "does not exist.");
break;
case -5002:
strcpy(err_msg, "Contact to the computer center.");
break;
default:
strcpy(err_msg,
"Application Error Message is not registered.");
}
}
break;
}
/* ROLLBACK */
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK;
fbchg_tu ( transf, E_TYPE, i, (char *)&type,0);
fbchg_tu ( transf, E_CODE, i, (char *)&err_code,0);
fbchg_tu ( transf, E_MSG, i, (char *)err_msg,0);
fbchg_tu ( transf, E_TMP, i, (char *)&tmp,0);
tpreturn(TPFAIL, 0, (char *)transf, 0L, 0L);
}
Makefile
The following example creates an emp_c.pc source as a Tmax application.
<emp_c.mk>
include $(ORACLE_HOME)/precomp/lib/env32.mk
ORALIBDIR = $(LIBHOME)
ORALIB = -L/home/oracle/OraHome/lib32/ -lclntsh -lld -lm
`cat /home/oracle/OraHome/lib32/sysliblist` -lm -lc_r -lpthreads
TARGET = emp_c
APOBJS = emp_c.o
NSDLOBJ = $(TMAXDIR)/lib/sdl.o
#CC
CC=cc
#Oracle
LIBS = -lsvr -loras
OBJS = $(APOBJS) $(SVCTOBJ)
SVCTOBJ = $(TARGET)_svctab.o
CFLAGS = -q32 -O -I$(TMAXDIR)
LDFLAGS = -brtl
APPDIR = $(TMAXDIR)/appbin
SVCTDIR = $(TMAXDIR)/svct
TMAXLIBDIR = $(TMAXDIR)/lib
#
.SUFFIXES : .c
.c.o:
$(CC) $(CFLAGS) $(LDFLAGS) -c $<
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -L$(TMAXLIBDIR) -o $(TARGET)
-L$(ORALIBDIR) $(ORALIB) $(OBJS) $(LIBS) $(NSDLOBJ)
mv $(TARGET) $(TMAXDIR)/appbin
$(APOBJS): $(TARGET).pc
proc iname=emp_c include=$(TMAXDIR) define=__LINUX_ORACLE_PROC__
$(CC) $(CFLAGS) $(LDFLAGS) -c $(TARGET).c
$(SVCTOBJ):
touch $(SVCTDIR)/$(TARGET)_svctab.c
$(CC) $(CFLAGS) $(LDFLAGS) -c $(SVCTDIR)/$(TARGET)_svctab.c
#
clean:
-rm -f *.o core $(TARGET) $(TARGET).lis