【问题标题】:Unexpected error running stored oracle PL/SQL proceedure运行存储的 oracle PL/SQL 过程出现意外错误
【发布时间】: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


【解决方案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。这些参数与绑定数组有关。由于我使用的程序采用单个值输入/输出,因此我已将这些输入配置为数组大小为 1。Evendently 数组中包含 1 个项目的项目数组与单个项目不同(在 oracle 看来)。因此,我的参数的数据类型是错误的,因为它是一个整数数组和一个数字数组,而第一个数组是 varchar(255) 的数组。

将所有这些参数设置为 0 或 NULL 以解决问题。

感谢阅读!

【讨论】:

    【解决方案2】:

    我认为你不需要指定空参数,你已经有 DEFAULT NULL 用于此目的

    可能是这样的:

    char sql[] = "BEGIN PTAPI.FORMATMESSAGE(193,:P_ERRNUM,:P_ERRMSG); END;\0"
    

    【讨论】:

    • 试一试,没有变化,仍然是同样的错误。不过感谢您的想法!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多