Я пытаюсь вызвать хранимую процедуру (на oracle db 11g) из клиента на основе OCI. Процедура содержит один параметр OUT для типа объекта.OCI: Как связать выходной параметр типа объекта
Проблема: я всегда получаю «ORA-21525: номер атрибута или (элемент коллекции по индексу)% s нарушил его ограничения».
Я был бы очень признателен, если бы кто-нибудь мог дать мне подсказку, что может быть причиной.
Примечание: Интересно, что все работает нормально в следующих случаях:
- заменяет тип возвращаемого от типа объекта к вложенной таблице таких объектов.
- Я заменяю тип возвращаемого типа на некоторый примитивный тип, например. NUMBER
- Я делаю это направление параметра IN и привязываю его таким же образом.
Кроме того, я обнаружил следующие вещи:
- Та же ошибка присутствует, независимо от того, если я возвращать результат в качестве параметра OUT из процедуры, или если I пользователя RETURN из функции.
- Если я попытаюсь вызвать хранимую процедуру с помощью PLSQL-скрипта, все будет выглядеть так, как ожидалось, без ошибок.
- Я также попытался создать параллельную структуру C++ из двух полей OCINumber и использовать ее объект вместо вызова 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;
С ++ ОКИ код (без инициализации соединения для краткости). Примечание. Я использую 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;
// ...
Заранее спасибо.