База данных, к которой я обращаюсь, имеет целый 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
Мой код для вызова процедуры приведен ниже [оператор и ошибка — это дескрипторы 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
Это дает кому-нибудь какие-либо идеи? Спасибо!