Непредвиденная ошибка при запуске хранимой процедуры оракула PL/SQL

База данных, к которой я обращаюсь, имеет целый 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

Это дает кому-нибудь какие-либо идеи? Спасибо!


person Josh    schedule 13.10.2015    source источник
comment
Каковы фактические типы данных столбцов в таблице ошибок?   -  person Alex Poole    schedule 13.10.2015
comment
errmsgs.error имеет тип NUMBER, а errmsgs.message имеет тип VARCHAR2 с шириной столбца 255 символов.   -  person Josh    schedule 13.10.2015
comment
Вы уверены, что старый клиент и новый клиент подключаются к одной и той же базе данных и одной и той же схеме — вы не просто видите другую версию пакета, чем вы ожидаете, может быть, старую или новую копию, которая была изменена? Что вы увидите, если подключитесь под тем же пользователем, что и ваш клиент, и опишите пакет? (Звучит очевидно, но можно и исключить...)   -  person Alex Poole    schedule 13.10.2015
comment
Я подключаюсь к одной и той же базе данных с одинаковыми учетными данными в обоих случаях. Я на 99,999% уверен, что проблема не в этом. В любом случае смотрите мои обновления выше; Я нашел лучшую тестовую процедуру, в которой доступен полный код PL/SQL. Спасибо за помощь Алексею!   -  person Josh    schedule 13.10.2015


Ответы (2)


Я заработал.

Проблема была в моих вызовах привязки. Я изменил их следующим образом;

OCIBindByName(statement,&bind1,err,(text*)":P_ERRNUM",-1,&errnum, sizeof(long),SQLT_INT,NULL,***NULL***,NULL,0,***NULL***,OCI_DEFAULT); //bind errnum
OCIBindByName(statement,&bind2,err,(text*)":P_ROWCNT",-1,&rowcnt, sizeof(long),SQLT_INT,NULL,***NULL***,NULL,0,***NULL***,OCI_DEFAULT); //bind rowcnt

Измененные параметры: curlep, alenp и maxarr_len. Эти параметры связаны с привязкой МАССИВОВ. Поскольку процедуры, которые я использую, принимают одиночные значения в/из, я настроил эти входы для размера массива 1. Даже массив элементов с 1 элементом в массиве не совпадает (в уме оракула) как один элемент. Таким образом, типы данных для моих параметров были неправильными, потому что это был МАССИВ целых чисел и МАССИВ чисел, а для первого - МАССИВ varchar (255).

Установка всех этих параметров на 0 или NULL, если применимо, устранила проблему.

Спасибо за чтение!

person Josh    schedule 13.10.2015

Я думаю, вам не нужно указывать пустые параметры, у вас уже есть DEFAULT NULL для этой цели

Так может быть и так:

char sql[] = "BEGIN PTAPI.FORMATMESSAGE(193,:P_ERRNUM,:P_ERRMSG); END;\0"
person Tatiana    schedule 13.10.2015
comment
Попробовал, без изменений, все та же ошибка. Хотя за идею спасибо! - person Josh; 13.10.2015