PowerBuilder(PB)和Oracle分别是前端开发工具和RD
BMS的主流产品。PB提供了两种与Oracle连接的接口:Pow
erSoft内置的数据库接口(Native Database Interface)
和ODBC接口。本文介绍使用PB60内置Oracle接口的方法
,包括数据描述文件的设置、存储过程的调用和存储过程
作为数据窗口数据源的操作方法等内容,使用的RDBMS的Or
acle 73。
PowerBuilder与Oracle的连接
假定已安装Oracle客户端应用程序。可用Sqlplus或T
nsping等是否能连接到Oracle数据库,确定在SQLNET配
置文件中使用的数据库别名(Database Alias,又称服务
器名,Server Name)。如有疑问,可在Oracle客户端程序
目录下tnsname.ora文件中找到。另外保证搜索路径已包括
SQLNET应用程序的安装目录(如C:/ORAWIN95/BIN)。
进入PB的Database Profiles画笔,可看到所有已安
装的数据库接口(PB60缺省安装的是Oracle 73版的接
口,如使用低版本的Oracle,需在安装时指定),选择“O7
3 Oracle 73”,点击“New”按钮,进入Database Pro
file Setup对话框。在“Connection”页输入下列信息:
Profile Name:为该Database Profile起一个有意义
的名称;
Server:@TNS:ServerName,其中ServerName为上述数
据库别名(服务器名),如@TNS:ORA73;
Login ID:Oracle数据库中实际的用户名,由于PB初
次连接到数据库时要自动建立五个系统表(PowerBuilder
Catalog Table:PBCATTBL,PBCATCOL,PBCATEDT,PBCATFMT,
PBCATVLD,存储表的扩展属性),因此第一个连接到Oracle
的用户必须具有建表、给PUBLIC角色授权等权限。例如可
用SYSTEM用户进行第一次连接,此后的连接对用户则无特
殊要求;
Password:该用户的口令。
设置上述内容后,即可连上Oracle。为优化数据库连
接,还可设置下列选项:
Prompt for Database Information:连接时是否提
示用户输入用户名和口令;
Generate Trace:启动DB跟踪工具,跟踪连接;
Thread Safe:开发需要多线程环境支持的分布式应
用时,选择该项。缺省为未选,适用于非分布应用;
PBDBMS:与存储过程调用方式有关的参数。Oracle为
72或更高版本时,清除该选项,此时带IN OUT参数的存
储过程可作为数据窗口数据源。72版本以下,选择该项
,调用PBDBMS.Put-Line建立存储过程的SQL语句,缺省
是选中;
Commit on Disconnect:断开连接时,指定提交或回
退未提交的事务;
Case Sensitive:连接的Oracle服务器是否区分大小
写。注意该项选中时,所有主键、包含主键的表名、外键
须全为大写字符。
PowerBuilder Catalog Tables Owner:指定拥有PB
系统表的用户,缺省为“SYSTEM”。如果要使用多种显示
格式或有效性规则,可以在不同的用户下建立几套系统表
;
Table Criteria:指定满足哪些条件的表、视图和同
义词可在“Select Tables”对话框中显示出来。例如DEV
用户下销售子系统的表都以SALE开头,则可以用SALE%、
DEV、“TABLE”、“VIEW”指定只显示DEV用户以SALE开
头的表和视图;
Asynchronous:选择该项,可在一个复杂的SQL语句
执行过程中,返回第一行结果前,切换到其他操作;
Number of Seconds to Wait:若上一项选中,还可
进一步通过该项指定检索数据时,等待数据库响应的时间
;
Retrieve Blocking Factor:决定数据窗口对象一次
可从数据库取出的记录数;
Number of SQL Staments Cached:PB可将数据窗口
对象产生的SQL语句和嵌入式SQL语句保存在SQL语句缓冲区
,该参数指定缓冲区为PB保留的SQL语句数目。该数值可
由下式计算:SQLCache=服务器OPEN—CURSORS数-5(保留
的游标数)-本连接预期使用的最大游标数;
Disable Bind:指定是否将输入变量与SQL语句绑定
,此参数影响PB为数据窗口对象生成INSERT语句的方式;
Static Bind:数据窗口对象检索数据前是否检测SEL
ECT语句的合法性;
在Syntax页,还可指定日期、时间的格式等。在Prev
iew页可查看Database Profile设置对应的PowerScript写
法。
Oracle存储过程的使用
归纳起来PB60中调用Oracle存储过程有以下四种方
法。
方法一:以关键字RPCFUNC声明存储过程;
方法二:以DECLARE PROCEDURE语句声明存储过程;
方法三:以动态SQL语句实现;
方法四:调用函数PBDBMS.Put-Line。
一般情况下,方法一能得到较好的运行效率和更完善
的功能。因此推荐使用方法一。但是某些类型的存储过程
只能使用其他方法。以下重点介绍方法一和方法二。
两种方法比较起来,有以下几点主要区别:
1)方法一适用于具有IN、OUT和IN OUT参数的存储过
程,而方法二仅支持IN和OUT参数,不支持IN OUT参数;
2)方法一对参数的数目无限制,方法二最多支持255
个参数;
3)方法一不支持记录(Recorder)的传递,方法二可传
递和接收记录。
方法一操作步骤:
1)在用户对象画笔中创建一个Class-Standard类型
的,从Transaction继承的用户对象。
2)在此用户对象中,声明Local External Functions
,将存储过程以RPCFUNC关键字声明为外部函数。在Decla
re Local External Functions对话框中按Procedures按
钮选择要调用的后台存储过程,或直接输入类似subroutin
e TEST(long id,ref string name)RPCFUNC ALIAS FOR
“DEVTEST”的语句。例如中DEVTEST的参数为(id IN
NUMBER,name IN OUT VARCHAR2)。
3)保存该用户对象。
4)在Application画笔中,进入应用属性对话框,在V
ariable Types页,将上Transaction用户对象设置为缺省
的全局变量SQLCA。
5)脚本中,编码调用相应的外部函数。形式:SQLCA
函数名(参数)。如可用“SQLCATEST(ln—id,ls—name
);”调用例子中定义的DEVTEST存储过程。其中ln—id,
ls—name为调用参数。
方法一注意事项:
1)由于PB中String类型的数据长度是动态分配的,因
此对Ref String类型的参数,每次调用前需要申请足够的
空间。例如上例从输入的id值检索name,后台声明的NAME
数据类型为VARCHAR2(30),每次调用SQLCATEST前需要
用ls—name=SPACE(30)置ls—name为足够长度的空串。
2)类似地当传递的参数为数组(后台称PL/SQL Table)
时,声明参数为相应类型的动态数组,并在每次调用前设
置数组上界为足够大的值。例如:DEV用户的DEPT包中声
明了TYPE tbl—name IS TABLE OF VARCHAR2(30) INDEX B
Y BINARY—INTEGER;存储过程EMP—OF—DEPT(dept—id
IN NUMBER,name OUT DEPT.tbl—name)返回部门编写为de
pt—id的部门的所有员工,置name数组中。假定所有部门
的员工数目不超过100,则可用以下语句声明和调用DEV
EMP—OF—DEPT:
Declare External Functions对话框中:
Subroutine EMP—OF—DEPT(long dept—id,ref str
ing name[]) RPCFUNC ALIAS FOR ″DEV.EMP—OF—DEPT
″
PowerScript脚本中:
long ln=dept—id
string lsa—name[]
……
lsa—name[100]=″ //置动态数组lsa—name上界为
100
ln—dept—id=2
SQLCA.EMP—OF—DEPT(ln—dept—id,lsa—name) /
/检索部门2的所有员工的名字
方法二使用方法:
在脚本中加入如下编码(以DEVTEST为例):
long ln—id
string ls—name
ln—id=100
DECLARE test PROCEDURE FOR DEV.TEST(:ln—id);
//test有一个IN参数,一个OUT参数
EXECUTE test;
FETCH test INTO:ls—name;
方法三使用方法:
根据输入输出参数的不同,PB中的动态SQL语句有四
种格式:1)无输入输出参数;2)只有输入参数,无输出参
数;3)有确定数目输入输出参数;4)输出结果列的数目不
定。其中第1)、第2)中格式的动态SQL语句也可用来调用简
单的存储过程。
1)没有输入输出参数的存储过程。例如DEVDEMO1存
储过程没有输入输出参数,可用下列语句调用:
sqlstring=″EXECUTE DEMO1()″
EXECUTE IMMEDIATE:sqlstring;
2)只有输入参数的存储过程。例如DEV.DEMO2(name I
N VARCHAR2,birthday IN DATE)
PREPARE SQLSA FROM ″EXECUTE DEMO2(?,?);″
EXECUTE SQLSA USING:ls—name,:ldt—birthday;
如果是72以下版本的Oracle,可用方法四PBDMBS.P
ut—Line()函数调用建立存储过程。此时需选上Database
Profile中的PBDBMS复选框。
存储过程作为数据窗口的数据源
以一个简单数据窗口(显示服务器的系统时间)为例说
明怎样创建存储过程作为数据源的数据窗口。
1)在某个包(如PACK—TYPE)中定义日期类型的Record
er自定义数据类型datarec;
2)创建返回系统时间的存储过程:
PROCEDURE get—sysdata(sysdt IN OUT PACK-TYPE
.datarec)IS
BEGIN
open sysdt for select sysdate from dual;
END;
3)新建数据窗口,数据源选择Stored Procedure;
4)在随后的Select Stored Procedure对话框中选择g
et—sysdate即可。
如果作为数据源的存储过程有IN参数,则这些参数就
是数据窗口的检索参数(Retrieve Argument)。
BMS的主流产品。PB提供了两种与Oracle连接的接口:Pow
erSoft内置的数据库接口(Native Database Interface)
和ODBC接口。本文介绍使用PB60内置Oracle接口的方法
,包括数据描述文件的设置、存储过程的调用和存储过程
作为数据窗口数据源的操作方法等内容,使用的RDBMS的Or
acle 73。
PowerBuilder与Oracle的连接
假定已安装Oracle客户端应用程序。可用Sqlplus或T
nsping等是否能连接到Oracle数据库,确定在SQLNET配
置文件中使用的数据库别名(Database Alias,又称服务
器名,Server Name)。如有疑问,可在Oracle客户端程序
目录下tnsname.ora文件中找到。另外保证搜索路径已包括
SQLNET应用程序的安装目录(如C:/ORAWIN95/BIN)。
进入PB的Database Profiles画笔,可看到所有已安
装的数据库接口(PB60缺省安装的是Oracle 73版的接
口,如使用低版本的Oracle,需在安装时指定),选择“O7
3 Oracle 73”,点击“New”按钮,进入Database Pro
file Setup对话框。在“Connection”页输入下列信息:
Profile Name:为该Database Profile起一个有意义
的名称;
Server:@TNS:ServerName,其中ServerName为上述数
据库别名(服务器名),如@TNS:ORA73;
Login ID:Oracle数据库中实际的用户名,由于PB初
次连接到数据库时要自动建立五个系统表(PowerBuilder
Catalog Table:PBCATTBL,PBCATCOL,PBCATEDT,PBCATFMT,
PBCATVLD,存储表的扩展属性),因此第一个连接到Oracle
的用户必须具有建表、给PUBLIC角色授权等权限。例如可
用SYSTEM用户进行第一次连接,此后的连接对用户则无特
殊要求;
Password:该用户的口令。
设置上述内容后,即可连上Oracle。为优化数据库连
接,还可设置下列选项:
Prompt for Database Information:连接时是否提
示用户输入用户名和口令;
Generate Trace:启动DB跟踪工具,跟踪连接;
Thread Safe:开发需要多线程环境支持的分布式应
用时,选择该项。缺省为未选,适用于非分布应用;
PBDBMS:与存储过程调用方式有关的参数。Oracle为
72或更高版本时,清除该选项,此时带IN OUT参数的存
储过程可作为数据窗口数据源。72版本以下,选择该项
,调用PBDBMS.Put-Line建立存储过程的SQL语句,缺省
是选中;
Commit on Disconnect:断开连接时,指定提交或回
退未提交的事务;
Case Sensitive:连接的Oracle服务器是否区分大小
写。注意该项选中时,所有主键、包含主键的表名、外键
须全为大写字符。
PowerBuilder Catalog Tables Owner:指定拥有PB
系统表的用户,缺省为“SYSTEM”。如果要使用多种显示
格式或有效性规则,可以在不同的用户下建立几套系统表
;
Table Criteria:指定满足哪些条件的表、视图和同
义词可在“Select Tables”对话框中显示出来。例如DEV
用户下销售子系统的表都以SALE开头,则可以用SALE%、
DEV、“TABLE”、“VIEW”指定只显示DEV用户以SALE开
头的表和视图;
Asynchronous:选择该项,可在一个复杂的SQL语句
执行过程中,返回第一行结果前,切换到其他操作;
Number of Seconds to Wait:若上一项选中,还可
进一步通过该项指定检索数据时,等待数据库响应的时间
;
Retrieve Blocking Factor:决定数据窗口对象一次
可从数据库取出的记录数;
Number of SQL Staments Cached:PB可将数据窗口
对象产生的SQL语句和嵌入式SQL语句保存在SQL语句缓冲区
,该参数指定缓冲区为PB保留的SQL语句数目。该数值可
由下式计算:SQLCache=服务器OPEN—CURSORS数-5(保留
的游标数)-本连接预期使用的最大游标数;
Disable Bind:指定是否将输入变量与SQL语句绑定
,此参数影响PB为数据窗口对象生成INSERT语句的方式;
Static Bind:数据窗口对象检索数据前是否检测SEL
ECT语句的合法性;
在Syntax页,还可指定日期、时间的格式等。在Prev
iew页可查看Database Profile设置对应的PowerScript写
法。
Oracle存储过程的使用
归纳起来PB60中调用Oracle存储过程有以下四种方
法。
方法一:以关键字RPCFUNC声明存储过程;
方法二:以DECLARE PROCEDURE语句声明存储过程;
方法三:以动态SQL语句实现;
方法四:调用函数PBDBMS.Put-Line。
一般情况下,方法一能得到较好的运行效率和更完善
的功能。因此推荐使用方法一。但是某些类型的存储过程
只能使用其他方法。以下重点介绍方法一和方法二。
两种方法比较起来,有以下几点主要区别:
1)方法一适用于具有IN、OUT和IN OUT参数的存储过
程,而方法二仅支持IN和OUT参数,不支持IN OUT参数;
2)方法一对参数的数目无限制,方法二最多支持255
个参数;
3)方法一不支持记录(Recorder)的传递,方法二可传
递和接收记录。
方法一操作步骤:
1)在用户对象画笔中创建一个Class-Standard类型
的,从Transaction继承的用户对象。
2)在此用户对象中,声明Local External Functions
,将存储过程以RPCFUNC关键字声明为外部函数。在Decla
re Local External Functions对话框中按Procedures按
钮选择要调用的后台存储过程,或直接输入类似subroutin
e TEST(long id,ref string name)RPCFUNC ALIAS FOR
“DEVTEST”的语句。例如中DEVTEST的参数为(id IN
NUMBER,name IN OUT VARCHAR2)。
3)保存该用户对象。
4)在Application画笔中,进入应用属性对话框,在V
ariable Types页,将上Transaction用户对象设置为缺省
的全局变量SQLCA。
5)脚本中,编码调用相应的外部函数。形式:SQLCA
函数名(参数)。如可用“SQLCATEST(ln—id,ls—name
);”调用例子中定义的DEVTEST存储过程。其中ln—id,
ls—name为调用参数。
方法一注意事项:
1)由于PB中String类型的数据长度是动态分配的,因
此对Ref String类型的参数,每次调用前需要申请足够的
空间。例如上例从输入的id值检索name,后台声明的NAME
数据类型为VARCHAR2(30),每次调用SQLCATEST前需要
用ls—name=SPACE(30)置ls—name为足够长度的空串。
2)类似地当传递的参数为数组(后台称PL/SQL Table)
时,声明参数为相应类型的动态数组,并在每次调用前设
置数组上界为足够大的值。例如:DEV用户的DEPT包中声
明了TYPE tbl—name IS TABLE OF VARCHAR2(30) INDEX B
Y BINARY—INTEGER;存储过程EMP—OF—DEPT(dept—id
IN NUMBER,name OUT DEPT.tbl—name)返回部门编写为de
pt—id的部门的所有员工,置name数组中。假定所有部门
的员工数目不超过100,则可用以下语句声明和调用DEV
EMP—OF—DEPT:
Declare External Functions对话框中:
Subroutine EMP—OF—DEPT(long dept—id,ref str
ing name[]) RPCFUNC ALIAS FOR ″DEV.EMP—OF—DEPT
″
PowerScript脚本中:
long ln=dept—id
string lsa—name[]
……
lsa—name[100]=″ //置动态数组lsa—name上界为
100
ln—dept—id=2
SQLCA.EMP—OF—DEPT(ln—dept—id,lsa—name) /
/检索部门2的所有员工的名字
方法二使用方法:
在脚本中加入如下编码(以DEVTEST为例):
long ln—id
string ls—name
ln—id=100
DECLARE test PROCEDURE FOR DEV.TEST(:ln—id);
//test有一个IN参数,一个OUT参数
EXECUTE test;
FETCH test INTO:ls—name;
方法三使用方法:
根据输入输出参数的不同,PB中的动态SQL语句有四
种格式:1)无输入输出参数;2)只有输入参数,无输出参
数;3)有确定数目输入输出参数;4)输出结果列的数目不
定。其中第1)、第2)中格式的动态SQL语句也可用来调用简
单的存储过程。
1)没有输入输出参数的存储过程。例如DEVDEMO1存
储过程没有输入输出参数,可用下列语句调用:
sqlstring=″EXECUTE DEMO1()″
EXECUTE IMMEDIATE:sqlstring;
2)只有输入参数的存储过程。例如DEV.DEMO2(name I
N VARCHAR2,birthday IN DATE)
PREPARE SQLSA FROM ″EXECUTE DEMO2(?,?);″
EXECUTE SQLSA USING:ls—name,:ldt—birthday;
如果是72以下版本的Oracle,可用方法四PBDMBS.P
ut—Line()函数调用建立存储过程。此时需选上Database
Profile中的PBDBMS复选框。
存储过程作为数据窗口的数据源
以一个简单数据窗口(显示服务器的系统时间)为例说
明怎样创建存储过程作为数据源的数据窗口。
1)在某个包(如PACK—TYPE)中定义日期类型的Record
er自定义数据类型datarec;
2)创建返回系统时间的存储过程:
PROCEDURE get—sysdata(sysdt IN OUT PACK-TYPE
.datarec)IS
BEGIN
open sysdt for select sysdate from dual;
END;
3)新建数据窗口,数据源选择Stored Procedure;
4)在随后的Select Stored Procedure对话框中选择g
et—sysdate即可。
如果作为数据源的存储过程有IN参数,则这些参数就
是数据窗口的检索参数(Retrieve Argument)。