【发布时间】:2015-01-29 16:36:15
【问题描述】:
我正在尝试从基于 OCI 的客户端调用存储过程(在 oracle db 11g 上)。该过程包含单个对象类型的 OUT 参数。
问题:我总是收到“ORA-21525:属性号或(索引处的集合元素)%s 违反了它的约束”错误。
如果有人能给我提示可能是什么原因,我将不胜感激。
注意:有趣的是,在以下情况下一切正常:
- 我将返回类型从对象类型替换为此类对象的嵌套表。
- 我将返回类型替换为一些原始类型,例如NUMBER
- 我将这个参数设置为方向 IN 并以同样的方式绑定它。
另外,我发现了以下几点:
- 无论我是从过程中将结果作为 OUT 参数返回还是用户从 FUNCTION 中返回,都会出现相同的错误。
- 如果我尝试通过 PLSQL 脚本调用存储过程,一切都会按预期进行,没有错误。
- 我还尝试创建由两个 OCINumber 字段组成的“并行”C++ 结构并使用它的对象而不是调用 OCIObjectNew(),但得到了同样的错误。
- 我也尝试设置
pOutParam = NULL,并绑定它,但是我得到“访问冲突,从位置00000读取”。
这里是代码。 PLSQL 对象类型:
CREATE OR REPLACE TYPE dl_fake_type AS OBJECT
(
attr_one NUMBER(12,0),
attr_two NUMBER(12,0)
);
/
过程(为了简洁,我跳过过程声明)
PROCEDURE dl_fake_fun(out_result OUT dl_fake_type)
IS
l_result dl_fake_type;
BEGIN
SELECT dl_fake_type(23, 35) INTO l_result FROM DUAL;
out_result := l_result;
END dl_fake_fun;
C++ OCI 代码(为简洁起见,没有连接初始化)。注意:我使用 MSVS2013 和一些 C++11 特性,比如 std::string::front() 方法。
// ...
typedef basic_string<OraText, char_traits<OraText>, allocator<OraText> > OraTextString;
typedef basic_ostringstream<OraText, char_traits<OraText>, allocator<OraText> > OraOStringStream;
// Check if ociStatus == OCI_SUCCESS. If not, then print error and assert.
void checkOciStatus(const sword ociStatus, OCIError * errorHandle = NULL);
// ...
const OraTextString DL_FAKE_TYPE = (OraText const *)"DL_FAKE_TYPE";
const OraTextString outParamName = (OraText const *)":out_param";
OraOStringStream query(ios::ate);
query << "BEGIN my_dummy_pkg.dl_fake_fun(" << outParamName << "); END;";
const OraTextString & queryString = query.str();
OCIStmt * statement;
const ub4 executionMode = OCI_DEFAULT;
checkOciStatus(OCIHandleAlloc(envhp, (void **)&statement, OCI_HTYPE_STMT, /* xtramemsz */ 0, /* usrmempp */ NULL), errhp);
checkOciStatus(OCIStmtPrepare(statement, errhp, queryString.c_str(), queryString.length(), OCI_NTV_SYNTAX, executionMode), errhp);
const OraTextString schemaName = (OraText const *)"MY_SCHEMA_NAME";
OCIType * typeDescriptor = NULL;
checkOciStatus(
OCITypeByName(
envhp,
errhp,
svchp,
schemaName.c_str(),
schemaName.size(),
DL_FAKE_TYPE.c_str(),
DL_FAKE_TYPE.length(),
/* version name */ NULL,
/* version name length */ 0,
OCI_DURATION_SESSION,
OCI_TYPEGET_HEADER,
&typeDescriptor
),
errhp
);
OCIBind* bindHandle = NULL;
checkOciStatus(OCIBindByName(statement, &bindHandle, errhp, outParamName.c_str(), outParamName.length(), NULL, 0, SQLT_NTY, NULL, NULL, NULL, 0, NULL, executionMode), errhp);
void * pOutParam = NULL;
checkOciStatus(OCIObjectNew(envhp, errhp, svchp, OCI_TYPECODE_REF, typeDescriptor, NULL, OCI_DURATION_DEFAULT, /* true = value, false = ref */ FALSE, &pOutParam), errhp);
checkOciStatus(OCIBindObject(bindHandle, errhp, typeDescriptor, &pOutParam, NULL, NULL, 0), errhp);
checkOciStatus(OCIStmtExecute(svchp, statement, errhp, 1, 0, NULL, NULL, executionMode), errhp);
cout << "executed." << endl;
// ...
提前致谢。
【问题讨论】:
标签: oracle stored-procedures plsql oracle-call-interface