运行存储的oracle PL / SQL进程

时间:2015-10-13 13:27:18

标签: oracle stored-procedures plsql oci

我正在访问的数据库在几个包中有一个完整的存储过程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

这会给任何人任何想法吗? 谢谢!

2 个答案:

答案 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"