我正在访问的数据库在几个包中有一个完整的存储过程API(几百个)。我正在研究新的客户端软件以与此数据库进行交互,我需要使用OCI调用这些存储过程。由于我是新手,我决定先从最简单的开始。它不起作用。
如果我能获得存储过程的实际PL / SQL代码会很有帮助。该程序包不在我的用户架构中,但我对它有执行权限。当我查询ALL_SOURCE视图时,我得到包声明,但不是包体。我也尝试了dbms_metadata.get_ddl视图,但它只是说“在模式中找不到包PTAPI”。有没有其他方法可以从包体中获取实际的PL / SQL代码?
这是我尝试使用的示例过程的PL / SQL包声明。在给定错误代码和一些取决于特定错误代码的可选参数的情况下,这个特定的消息会创建一个文本错误消息。
-- format an error message from ERRMSGS table
PROCEDURE formatmessage(
p_error IN errmsgs.error%TYPE -- index into ERRMSGS
, p_errnum OUT errmsgs.error%TYPE -- adjusted error number
, p_errmsg OUT errmsgs.MESSAGE%TYPE -- formatted message
, p_a IN VARCHAR2 DEFAULT NULL
, p_b IN VARCHAR2 DEFAULT NULL
, p_c IN VARCHAR2 DEFAULT NULL
, p_d IN VARCHAR2 DEFAULT NULL
, p_e IN VARCHAR2 DEFAULT NULL
); -- formatmessage
我调用该过程的代码在[statement和err是从更高的位置传入此函数的OCI句柄]
char errmsg[256]; //buffer to receive the error message
long errnum; //buffer to receive the adjusted error number
memset(errmsg,0,256); errnum = 0; //start the message buffer empty
OCIBind* bind1 = NULL, *bind2 = NULL; //to receive the bind handles
ub4 curelep1 = 1; //1 errnum element
ub4 curelep2 = 1; //1 errmsg element
ub2 alenp1 = sizeof(long); //errnum element size
ub2 alenp2 = 256; //errmsg element size
char sql[] = "BEGIN PTAPI.FORMATMESSAGE(193,:P_ERRNUM,:P_ERRMSG, '','','','',''); END;\0"
OCIStmtPrepare(statement,err,(text*)sql,strlen(sql),OCI_NTV_SYNTAX, OCI_DEFAULT); //parse the SQL statement
OCIBindByName(statement,&bind1,err,(text*)":P_ERRNUM",-1,&errnum, sizeof(long),SQLT_INT,NULL,&alenp1,NULL,1,&curelep1,OCI_DEFAULT); //bind errnum
OCIBindByName(statement,&bind2,err,(text*)":P_ERRMSG",-1,errmsg,256, SQLT_STR,NULL,&alenp2,NULL,1,&curelep2,OCI_DEFAULT); //bind errmsg
if(OCIStmtExecute(svcctx,statement,err,1,0,NULL,NULL,OCI_DEFAULT) != OCI_SUCCESS) //execute the statement
{
long errcode;
char errbuf[512];
OCIErrorGet (err,1,NULL,(sb4*)&errcode,(OraText*)errbuf,512, OCI_HTYPE_ERROR); //check to see what the error was
printf("ERROR %d - %s\n",errcode,errbuf);
return FAIL;
}
语句正确解析并且两个绑定成功,但是我在执行时遇到错误。我得到的错误是
ERROR 6550 - ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'FORMATMESSAGE'
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'FORMATMESSAGE'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
我对此错误感到困惑,因为我从正常运行的旧客户端软件模仿对此功能的调用。我肯定有正确的数量和类型的参数。有什么想法我会收到这个错误吗?
----更新----
我找到了一个更好的示例程序来测试。这个没有存储在一个包中,它是一个独立的过程,所以我有完整的PL / SQL代码。我得到完全相同的错误。它必须与我如何调用它们有关。谢谢你的任何想法。
这个从数据库中删除某种类型的项目(3个不同的表上的条目)。
这是PL / SQL
PROCEDURE DELSTL(comp IN 3DCOMPS.COMPID%TYPE,
rowcount OUT integer,
errorcode OUT number)
AS
tempcount INTEGER;
BEGIN
errorcode := 0;
DELETE FROM 3DCOMPS WHERE COMPID = comp;
tempcount := sql%rowcount;
IF (sql%rowcount < 1) THEN
errorcode := 330;
END IF;
DELETE FROM IDINF WHERE COMPID = comp;
IF (sql%rowcount < 1) THEN
errorcode := 332;
ELSIF (tempcount < sql%rowcount) THEN
tempcount := sql%rowcount;
END IF;
rowcount := tempcount;
DELETE FROM ATTLOC WHERE COMPID1 = comp OR COMPID2 = comp;
END;
这是我对此新测试程序的略微修改的代码
long errnum; //buffer to receive the error number
long rowcnt; //buffer to receive the row count
OCIBind* bind1 = NULL, *bind2 = NULL; //to receive the bind handles
ub4 curelep1 = 1; //1 errnum element
ub4 curelep2 = 1; //1 rowcnt element
ub2 alenp1 = sizeof(long); //errnum element size
ub2 alenp2 = sizeof(long); //rowcnt element size
char sql[] = "BEGIN DELSTL('FAKEIDNUM',:P_ROWCNT,:P_ERRNUM); END;\0"
OCIStmtPrepare(statement,err,(text*)sql,strlen(sql),OCI_NTV_SYNTAX, OCI_DEFAULT); //parse the SQL statement
OCIBindByName(statement,&bind1,err,(text*)":P_ERRNUM",-1,&errnum, sizeof(long),SQLT_INT,NULL,&alenp1,NULL,1,&curelep1,OCI_DEFAULT); //bind errnum
OCIBindByName(statement,&bind2,err,(text*)":P_ROWCNT",-1,&rowcnt, sizeof(long),SQLT_INT,NULL,&alenp2,NULL,1,&curelep2,OCI_DEFAULT); //bind rowcnt
if(OCIStmtExecute(svcctx,statement,err,1,0,NULL,NULL,OCI_DEFAULT) != OCI_SUCCESS) //execute the statement
{
long errcode;
char errbuf[512];
OCIErrorGet (err,1,NULL,(sb4*)&errcode,(OraText*)errbuf,512, OCI_HTYPE_ERROR); //check to see what the error was
printf("ERROR %d - %s\n",errcode,errbuf);
return FAIL;
}
我使用'FAKEIDNUM',因为我显然不希望在此测试期间实际删除任何内容。由于那些表中不存在,因此当程序结束时,rowcnt应为0,errnum应为332。
我得到与其他程序完全相同的错误。
ERROR 6550 - ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'DELSTL'
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'DELSTL'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
这会给任何人任何想法吗? 谢谢!
答案 0 :(得分:1)
我得到了它的工作。
问题出在我的绑定调用中。我把它们改成如下;
OCIBindByName(statement,&bind1,err,(text*)":P_ERRNUM",-1,&errnum, sizeof(long),SQLT_INT,NULL,***NULL***,NULL,0,***NULL***,OCI_DEFAULT); //bind errnum
OCIBindByName(statement,&bind2,err,(text*)":P_ROWCNT",-1,&rowcnt, sizeof(long),SQLT_INT,NULL,***NULL***,NULL,0,***NULL***,OCI_DEFAULT); //bind rowcnt
更改的参数是curelep,alenp和maxarr_len。这些参数与绑定ARRAYS有关。由于我使用的过程采用单个值输入/输出,我已经为数组大小为1配置了这些输入。甚至数组中包含1个项目的项目数组也不一样(在oracle的心目中)单个项目。因此,我的参数的数据类型是错误的,因为它是一个整数的ARRAY和一个数字的ARRAY,而第一个是varchar(255)的ARRAY。
将所有这些参数设置为0或NULL以解决问题。
感谢阅读!
答案 1 :(得分:0)
我认为您不需要指定空参数,为此目的已经有DEFAULT NULL
可能就是这样:
char sql[] = "BEGIN PTAPI.FORMATMESSAGE(193,:P_ERRNUM,:P_ERRMSG); END;\0"