【问题标题】:Calling an Oracle PL/SQL procedure in Java using a CallableStatement with a boolean IN parameter gives an PLS-00306 oracle error:使用带有布尔 IN 参数的 CallableStatement 在 Java 中调用 Oracle PL/SQL 过程会产生 PLS-00306 oracle 错误:
【发布时间】:2013-01-11 07:58:08
【问题描述】:

我在 Oracle 11g 上有一个 pl/sql 过程,它具有以下参数:

PROCEDURE validate_product
   ( product_id_in IN varchar2 , 
     username_in in varchar2, 
     source_in varchar2,    
     source_id_in varchar2 , 
     isEuProduct in boolean , 
     error_code out varchar2, 
     product_type out varchar2  
     )

我正在尝试使用以下代码从 java 中调用上述存储过程:

cstmt = getConnection().prepareCall("begin " + DBUtil.SCHEMANAME + ".PRODUCT_UTILITIES.validate_product(:1,:2,:3,:4,:5,:6,:7); end;");

cstmt.registerOutParameter(6, Types.CHAR); 
cstmt.registerOutParameter(7, Types.CHAR); 

cstmt.setString(1, productId);
cstmt.setString(2, username);
cstmt.setString(3, sourceName);
cstmt.setString(4, sourceId);
cstmt.setBoolean(5, isEUProduct);

cstmt.execute();

java变量的类型都是String,除了isEUProductboolean。每当我运行上述程序时,我都会收到以下错误:

PLS-00306: wrong number or types of arguments in call to validate_product ORA-06550: line 1, column 7: PL/SQL: Statement ignored"

我必须调试程序一百次,但一切似乎都是正确的类型并且参数的数量是正确的。

我完全不知道我做错了什么。用谷歌搜索后,我怀疑我可能没有正确设置布尔参数。

有什么想法吗?

【问题讨论】:

  • 我以为 JDBC 参数是用“?”标识的。

标签: java sql oracle jdbc plsql


【解决方案1】:

当我们遇到这个问题时我很惊讶,但是 Oracle JDBC 驱动程序不支持将布尔值传递到存储过程中......是的,我没有编造它:)

Boolean Parameters in PL/SQL Stored Procedures

JDBC 驱动程序不支持将 BOOLEAN 参数传递给 PL/SQL 存储过程。如果 PL/SQL 过程包含 BOOLEAN 值,您可以通过使用第二个 PL/SQL 过程包装 PL/SQL 过程来解决此限制,该过程接受作为 INT 的参数并将其传递给第一个存储过程。当调用第二个过程时,服务器执行从 INT 到 BOOLEAN 的转换。

【讨论】:

  • 哇,我没想到会这样。我怀疑这也可能是它不起作用的原因。谢谢。
  • 与 Oracle 一样,如果您等待足够长的时间,新版本中缺少的功能就会出现。从 12.2 开始可以使用本机 BOOLEAN 绑定。见例子here
【解决方案2】:

该限制有一个简单的解决方法,它不需要包装程序,只需将 PL/SQL 中的布尔参数包装在 CASE 语句中并使用整数进行绑定:

stmt = connection.prepareCall("begin" 
        +"  booleanFunc(par_bool => (CASE ? WHEN 1 THEN TRUE ELSE FALSE END)); "
        +"end;"
       );

// now bind integer, 1 = true, 0 = false
stmt.setInt(1, 0); // example for false

如果您的方法使用布尔值,您可以在绑定期间以相反的方式包装 Integer,例如:

// now bind integer, 1 = true, 0 = false
stmt.setInt(1, myBool ? 1 : 0); 

【讨论】:

  • CASE ? WHEN 0 THEN FALSE ... 可能会更安全,但这是一个不错的技巧!
【解决方案3】:

我认为这是问题

cstmt.registerOutParameter(6, Types.CHAR); 
cstmt.registerOutParameter(7, Types.CHAR); 

你像上面一样从java调用,但是你在过程中声明参数为varchar2,这意味着数据类型不匹配。

试试这个代码,

cstmt.registerOutParameter(6, Types.VARCHAR); 
cstmt.registerOutParameter(7, Types.VARCHAR); 

我希望这会奏效..

【讨论】:

    【解决方案4】:

    我怀疑 out 语句可能需要修改以下内容(因为过程中 out 参数的类型是 varchar2):-

    cstmt.registerOutParameter(6, Types.VARCHAR); 
    cstmt.registerOutParameter(7, Types.VARCHAR); 
    

    但是,如果这不起作用,请尝试将 prepareCall 语句也修改为以下内容:-

    cstmt = getConnection().prepareCall("{call " + DBUtil.SCHEMANAME + ".PRODUCT_UTILITIES.validate_product(?,?,?,?,?,?,?)}");
    

    【讨论】:

      【解决方案5】:

      从 Oracle 12.2 开始,有一个 JDBC Support for Binding PLSQL_BOOLEAN

      我将演示一个带有INOUTBOOLEAN参数的简单过程

      create or replace PROCEDURE proc_C (flag_in BOOLEAN, flag_out OUT BOOLEAN) as
      begin
        flag_out := flag_in;
      end;
      /
      

      很遗憾不能直接使用setBoolean绑定第一个参数。

      驱动程序Version 19.3.0.0.0 在这种情况下返回PLS-00306: wrong number or types of arguments in call to 'PROC_C'

      解决方法很简单,使用setObject(1,true,oracle.jdbc.OracleTypes.PLSQL_BOOLEAN)

      整个例子

      stmt = con.prepareCall("{ call proc_C(?,?)}") 
      stmt.setObject(1,false,oracle.jdbc.OracleTypes.PLSQL_BOOLEAN)
      stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.PLSQL_BOOLEAN) 
      stmt.execute()
      flag = stmt.getBoolean(2)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-10
        • 1970-01-01
        • 1970-01-01
        • 2021-04-04
        • 1970-01-01
        • 1970-01-01
        • 2020-12-26
        相关资源
        最近更新 更多