2016-06-20 2 views
0

Я прочитал каждую релевантную ссылку на эту проблему и подобные вопросы/ответы, ответ preveland - это первый набор whenever SQLERROR EXIT SQL.SQLCODE; Только тогда выполните запрос, а затем проверьте код возврата SQL Plus, используя : ERRORCODE=$?Ошибка обработки SQLPlus от Bash - не работает

Вот пример сценария:

GetAmountOfChunks() 
{ 
export CHUNK_AMOUNT=`sqlplus -s $CONSTR<<SQL 
    set heading off; 
    set trim on; 
    set feed off; 
    whenever SQLERROR EXIT SQL.SQLCODE; 
    select 1/0 from dual; 
    --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS; 
    /
SQL` 

Когда побежал режим отладки, это дает:

++ sqlplus -s USER/[email protected]/DB 
+ export 'CHUNK_AMOUNT=  select 1/0 from dual 
         * 
ERROR at line 1: 
ORA-01476: divisor is equal to zero' 
+ CHUNK_AMOUNT='  select 1/0 from dual 
         * 
ERROR at line 1: 
ORA-01476: divisor is equal to zero' 
+ ERRORCODE=0 
+ '[' 0 -ne 0 ']' 

Как вы можете видеть, возвращенный код 0! Я ожидал, если бы не 1476, то по крайней мере 196 (самое большее 8 байтов), но не 0, что указывает на успех!

Пожалуйста, помогите ...

Спасибо.

+0

Предоставьте полный код, который вы использовали вместо всего лишь фрагмента ... Мы не можем понять, что происходит, и проблема может быть в той части кода, которую вы не разделили. – Camusensei

ответ

2

Ваш ERRORCODE устанавливается в ноль, потому что это код выхода из подоболочки, в которой вы работаете SQL * Plus, viq обратные ссылки. Код выхода SQL * Plus - это 196, но вы не занимаетесь этим, и это не так просто сделать в heredoc. Вывод из процесса - это то, что вы захватываете - это не тот код выхода, это сообщение с запросом и ошибкой. И даже если бы вы могли его захватить, я не знаю, как бы вы отличали 196 от ошибки или от вашего фактического запроса.

Вы можете сделать что-то вроде выполнения запроса в блоке, который скрывает ошибку, и печатает либо значение по умолчанию, либо фактическое вычисленное значение, либо только посмотреть на последнюю строку вывода и попытаться ее интерпретировать; но вы все равно будете бороться с ним, показывая, что команда запускается. SQL * Plus имеет set echo off, но это ничего не делает с интерактивным сеансом, который по-прежнему относится к перенаправлению ввода.

Другой путь заключается в создании файла сценария и временно хранить выход:

echo " 
    set pages 0 
    set trim on 
    set feed off 
    set echo off 
    whenever SQLERROR EXIT FAILURE 
    select 1/0 from dual; 
    --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS; 
    exit 0; 
" > /tmp/GetAmountOfChunks_$$.sql 
sqlplus -s -l $CONSTR @/tmp/GetAmountOfChunks_$$.sql > /tmp/GetAmountOfChunks_$$.out 
if [[ $? -eq 0 ]]; then 
    export CHUNK_AMOUNT=`cat /tmp/GetAmountOfChunks_$$.out` 
else 
    # whatever you want to do on error; show output file? set default? 
    cat /tmp/GetAmountOfChunks_$$.out 
fi 

rm -f /tmp/GetAmountOfChunks_$$.sql /tmp/GetAmountOfChunks_$$.out 

Это создает (процесс конкретного) .sql файла; выполняет запись записи (за вычетом инструкции, через set echo off) в .out-файл; проверяет код выхода SQL * Plus; и если это нуль, получается результат из файла.

Как вы намекали, ссылаясь на SQL.SQLCODE, чтобы обнаружить ошибку из вашего сценария оболочки, это опасно, поскольку вы можете получить ошибку, которая обертывается до нуля, поэтому я использовал общий FAILURE. Если вам нужен реальный код ошибки, вы можете получить его из выходного файла.


Другой подход с использованием/SQL блок PL:

set -f 
CHUNK_AMOUNT=`sqlplus -s $CONSTR <<SQL 
    set heading off; 
    set trim on; 
    set feed off; 
    whenever SQLERROR EXIT FAILURE; 
    set serveroutput on; 
    declare 
     chunk_amount number; 
    begin 
     select 1/0 into chunk_amount from dual; 
     --SELECT COUNT(*) INTO chunk_amount FROM CNV_CHUNKS_PROC_STATUS; 
     dbms_output.put_line(chunk_amount); 
    exception 
     when others then 
     dbms_output.put_line(sqlcode); 
    end; 
    /
    exit 0 
SQL 
exit $?` 
ERRORCODE=$? 

Если/SQL пробегов блок PL затем ERRORCODE будет равен нулю и CHUNK_AMOUNT будет вычисленное значение, если оно успешно, или код SQL если он выдает исключение; так как это будет отрицательным (-1476 в вашем примере), вы можете проверить это, чтобы увидеть, ожидалось ли это, если вы ожидаете только положительных значений.

Если блок не может работать из-за синтаксической ошибки или неправильные учетные данные (обратите внимание на флаг -l я пробралась в), то ERRORCODE будет 1 и CHUNK_AMOUNT будет иметь текст сообщения об ошибке, например, ERROR: ORA-12154: TNS:could not resolve the connect identifier... или что-то на самом деле пошло не так.set -f останавливает * в сообщении об ошибке, которое расширяется в список файлов из текущего каталога.

Или еще проще и ближе к оригиналу:

set -f 
CHUNK_AMOUNT=`sqlplus -s $CONSTR <<SQL 
    set heading off; 
    set trim on; 
    set feed off; 
    whenever SQLERROR EXIT FAILURE; 
    select 1/0 from dual; 
    --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS; 
    exit 0 
SQL 
exit $?` 
ERRORCODE=$? 

и теперь ERRORCODE является 0 в случае успеха и CHUNK_AMOUNT имеет расчетное значение на какой-либо ошибке ERRORCODE является 1, вы можете проверить, что непосредственно, и фактическая ошибка всегда находится в CHUNK_AMOUNT - но только как строка, вы не получаете -1476 таким образом.

+0

Удивительный! хорошо выглядит, я собираюсь проверить это в ближайшее время, но меня беспокоит производительность. Это необходимо для процесса конверсии, в котором будут выполняться милилоны раз (не этот конкретный запрос, а другие в процессе будут) - если каждая запись на диск и чтение дважды, это значительно замедлит время завершения преобразования. Любые обходные пути для записи на HDD? – Carmageddon

+0

@Carmageddon - добавлены две версии без диска. Я думаю, что последнее самое простое и будет работать на то, что вы делаете. Зависит от того, хотите ли вы, чтобы CHUNKSIZE всегда сохранял только (отрицательный) код SQL. –

+1

Спасибо вам большое! последний будет отлично работать для большинства простых запросов и блоков PL/SQL для более сложных. BTW: его CHUNK_AMOUNT не CHUNKSIZE, пожалуйста, отредактируйте, чтобы в будущем он никого не смутил. – Carmageddon

Смежные вопросы