【发布时间】:2015-10-13 13:27:17
【问题描述】:
我正在访问的数据库在几个包中有一个完整的存储过程 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
这会给任何人任何想法吗? 谢谢!
【问题讨论】:
-
错误表中各列的实际数据类型是什么?
-
errmsgs.error 是 NUMBER 类型,errmsgs.message 是 VARCHAR2 类型,列宽 255 个字符
-
您确定旧客户端和新客户端连接到相同的数据库和相同的模式 - 您看到的不只是包的版本与您预期的不同,可能是旧的或新的副本被修改了?如果您以与客户相同的用户身份连接并描述包,您会看到什么? (听起来很明显,但不妨排除它......)
-
在这两种情况下,我都使用相同的凭据连接到同一个数据库。我有 99.999% 的信心这不是问题所在。无论如何,请参阅我上面的更新;我找到了一个更好的测试程序,它有完整的 PL/SQL 代码可用。感谢您的帮助亚历克斯!
标签: oracle stored-procedures plsql oracle-call-interface