【问题标题】:What is wrong with my Oracle RAW return param?我的 Oracle RAW 返回参数有什么问题?
【发布时间】:2019-06-07 11:13:54
【问题描述】:

我有一个带有以下签名和局部变量的存储过程:

PROCEDURE contract_boq_import(i_project_id IN RAW, 
                      i_boq_id IN RAW,
                      i_master_list_version IN NUMBER,
                      i_force_update_if_exists IN BOOLEAN, 
                      i_user_id IN NUMBER,
                      o_boq_rev_id OUT RAW) AS
  v_contract_id          RAW(16);
  v_contract_no          VARCHAR2(100);
  v_series_rev_id_count  NUMBER(1);
  v_project_id_count     NUMBER(5);
  v_now                  DATE;
  v_boq_import_rev_id    RAW(16);
  v_master_project_id    RAW(16);
  v_prj_duplicate_items  VARCHAR2(1000) := '';

我使用我们的 DAL 实用程序之一设置了一个输出参数:

var revParam = new byte[16];
dataHandler.CreateParameterRaw("o_boq_rev_id", revParam).Direction = ParameterDirection.Output;

CreateParameterRaw 声明为:

public DbParameter CreateParameterRaw(string name, object value)
{
  OracleParameter oracleParameter = new OracleParameter();
  oracleParameter.ParameterName = name;
  oracleParameter.OracleDbType = OracleDbType.Raw;
  oracleParameter.Value = value;
  this.Parameters.Add((DbParameter) oracleParameter);
  return (DbParameter) oracleParameter;
}

然后当我使用ExecuteNonQuery 执行该过程时,我收到以下错误:

Oracle.ManagedDataAccess.Client.OracleException
  HResult=0x80004005
  Message=ORA-06502: PL/SQL: numeric or value error: raw variable length too long
ORA-06512: at "ITIS_PRCDRS.PA_PRJ_IMP", line 1235

在第 1235 行抛出异常:

o_boq_rev_id := v_boq_import_rev_id;

从上面的过程声明中可以看出,v_boq_import_rev_id 的类型为RAW(16)o_boq_rev_id 的类型为OUT RAW,那么为什么第 1235 行的赋值会失败呢?我做错了什么?

PS:当我用普通的 PL/SQL 调用 proc 时,它执行得很好。

【问题讨论】:

  • 您使用的是哪个数据库和驱动程序版本?听起来您的参数默认为数据库不期望的最大大小,这可能是版本冲突。不确定是否可以将大小指定为 oracleParameter 设置的一部分?
  • 我的数据库是 Oracle 12c v12.1.0.2.0,我能找到的唯一“驱动程序”版本是 Oracle.ManagedDataAccess 包,它是 v4.122.1.0。我找不到任何指定参数大小的方法。我唯一尝试过的是传递各种大小的byte[](尤其是byte[16])和string vars 作为参数值,但似乎没有大小起作用。
  • oracleParameter.Size = 16 in CreateParameterRaw 不起作用吗?
  • @MatthewMcPeak 是的,这是缺少的,但在下面接受的答案中。

标签: oracle exception stored-procedures parameters


【解决方案1】:

OracleParameter 中,对于可能具有大小值的参数,默认大小为 0。 (官方参考here。)

这就是为什么您需要修改生成原始值的方法。您可以在下面找到修改后的方法:

public DbParameter CreateParameterRaw(string name, object value, int parameterSize)
{
  OracleParameter oracleParameter = new OracleParameter();
  oracleParameter.ParameterName = name;
  oracleParameter.OracleDbType = OracleDbType.Raw;
  oracleParameter.Value = value;
  oracleParameter.Size = parameterSize; /* THIS IS THE ADDED PARAMETER */
  this.Parameters.Add((DbParameter) oracleParameter);
  return (DbParameter) oracleParameter;
}

因此,您可以在调用 CreateParameterRaw 时传递大小,就像您在现有代码中所做的那样:

var revParam = new byte[16];
/* CHECK THE 16 value in the parameters that are sent to CreateParameterRaw */
dataHandler.CreateParameterRaw("o_boq_rev_id", revParam, 16).Direction = ParameterDirection.Output;

补充建议:为了保持苹果与苹果,我建议您可以将Direction参数也带入CreateParameterRaw方法。这样CreateParameterRaw就成为了生成参数的全责。


学分

【讨论】:

    【解决方案2】:

    这是一个有趣的问题,有一个奇怪的解决方案。

    实际上,在输出参数中使用 RAW 时,您必须在添加此参数时为其提供一些缓冲区空间。

    您能否为这个变量提供一些缓冲区空间并尝试以下操作:

    byte[] RAWPlaceholder = new byte[16];
    
    cmd.AddParameter(new OracleParameter("o_boq_rev_id", 
                                      OracleDbType.Raw,  
                                      16, 
                                      RAWPlaceholder, 
                                      ParameterDirection.Output);
    

    请分享上述练习的结果。

    谢谢

    【讨论】:

    • Oracle 不允许您在过程签名中指定参数的大小(输入或输出)。
    • 编辑了答案。谢谢!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-11
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    相关资源
    最近更新 更多