Програмування Oracle в середовищі UNIX

Взаємодія з Oracle з використанням Korn-оболонки UNIX


Інструментальне середовище


Для розуміння вмісту даної статті потрібно певний звід знань по SQL, PL / SQL і побудови скриптів в Korn-оболонці (Korn shell) ОС UNIX. Наведені приклади протестовані в наступної середи:



Якщо ви недостатньо знайомі з побудові скриптів в Korn-оболонці, раджу звернутися до моєї улюбленої книзі з даної теми "The new Korn Shell" by Morris Bolsky and David Korn [Prentice-Hall PTR, ISBN: 0-13-182700-6].


Для адміністраторів баз даних, а також для розробників UNIX є найбільш сприятливим середовищем для розміщення баз даних Oracle. Ці обидві технології протягом тривалого часу настільки довели свою відмінну гнучкість і підвищену стійкість, що більшість з нас забули про обережність. Я все ж вважаю, що ці дві "старі собаки" (two "old dogs") ще можуть викинути який-небудь новий трюк, тому зберігаю граничну уважність.


Мені видається, що чудова Korn-оболонка, що входить в чинний стандарту набір інструментарію UNIX, здатна надати найкращі можливості для будь-якого програміста. Незважаючи на те, що багато клієнтів Oracle ухиляються від активного застосування і підтримки розробок в середовищі UNIX, більшість же цілком згодні визнати право на існування "скрипта оболонки" ("shell script"), а також те, що "скрипт оболонки" є всім, у чому ми потребуємо для багатьох кінцевих додатків. У цій статті демонструється, як утиліта SQL * Plus може використовуватися також, як будь-яке інструментальне засіб UNIX. І ви зрозумієте, що взаємодія з базою даних Oracle за допомогою програм, які представляють собою "скрипти оболонки", просто, гнучко і динамічно. Це і є – шлях UNIX.


Короткий огляд


SQL * Plus вдало вписується в стандартні UNIX-потоки введення / виводу (IO stream; stream – абстрактний послідовний файл – ред.). Найпростіший спосіб продемонструвати це положення – треба виконати наступну UNIX-команду:



print “select * from dual;” / sqlplus -s scott/tiger


яка продукує наступний вихід:



D

X


Зауваження: прапорець "-s" пригнічує стандартний заголовок (banner) Oracle.


Як тільки ви усвідомили це, можливості використання SQL * Plus в UNIX можуть стати дуже захоплюючими. Ви можете без праці конструювати і запускати пропозиції динамічного SQL і PL / SQL (Dynamic SQL or PL / SQL). Є також механізм, доступний програмістові-розробнику скриптів оболонки, який запобігає фіксування (commit) і відкат (rollback) при виконанні транзакцій SQL * Plus.


Використовуючи канали (pipes) для передачі до SQL * Plus SQL-і PL/SQL- пропозицій, можна уникнути використання тимчасових файлів і конструювати SQL-і PL/SQL- пропозиції "на льоту" ("on-the-fly"). Канали можна також використовувати, щоб зібрати вихідний лістинг, генерований SQL * Plus (ідучи, тим самим, ще раз від тимчасових файлів), а також інтерпретувати цей вихідний лістинг інструментальними засобами UNIX. У цій статті для демонстрації технології комунікації UNIX / Oracle використовується простий UNIX-файл, що забезпечує інтерфейс з таблицею Oracle.


Чи працює Oracle належним чином?


Однією з перших завдань, необхідних від інтерфейсу, є перевірка, що цільова база даних Oracle реально готова до бізнес-діяльності. Я знаю, і використовував багато прийомів, як зробити це, але моє сьогоднішнє перевагу віддано запуску невеликого запиту з передбаченим результатом і перевірці цього результату. Якщо запит виконується, як очікується, то, ймовірно, що з Oracle все OK. Наступна функція Is_Oracle_OK виконує цю роботу:



#!/usr/bin/ksh
typeset -irx TRUE=0
typeset -irx FALSE=1


function Is_Oracle_OK
{
     if print “
          select dummy//”OK” from dual;
          ” / sqlplus -s scott/tiger / grep -q XOK
     then return ${TRUE}
     fi
     return ${FALSE}
}


if Is_Oracle_OK
then print “Oracle is up”


Цей скрипт запитує таблицю “dual”, А потім переглядає очікуваний рядковий вихід. Якщо все працює добре, то “XOK”. Зверніть увагу, що закладена обережність гарантує, що якщо Oracle відкидає представлений SQL-запит, то будь-яка частина згенерованого Oracle повідомлення про помилку не буде відповідати приймального набору критеріїв команди grep.


Динамічно створюваний SQL


Тепер, коли, використавши функцію Is_Oracle_OK, встановлено, що база даних знаходиться в операційному стані, ми хочемо вставити частину вмісту файлу / etc / passwd в таблицю. У цьому прикладі ми хочемо завантажити перше і п'яте поля (розмежовані символом "/") кожного рядка файлу, що починається з символу "r". Для того щоб трохи загострити ситуацію, в коді наступного прикладу тестова таблиця створюється, заповнюється, запитується і віддаляється. Ми запитуємо фіксацію (commit) після вставки в таблицю кожних чергових 10 записів, а також після останньої вставки. Зверніть увагу на використання змінних UNIX-середовища в SQL-пропозиції.


{
typeset TABLE=”example” # Name the table to load


          print “WHENEVER SQLERROR EXIT”
          print “WHENEVER OSERROR EXIT”
          print “set autocommit off”


print “create table ${TABLE}
     (
          user_name varchar2(16),
          user_description varchar2(64)
     );”


     typeset -i COUNT=0 # Count records inserted
     typeset FILE=/etc/passwd # The file to load
     typeset Item1 # Holds user name from passwd file
     typeset Item5 # Holds user description


                    grep -E “^r” ${FILE} / while read LINE
     do
          let COUNT=COUNT+1
          Item1=$(print ${LINE} / cut -d”/” -f1)
          Item5=$(print ${LINE} / cut -d”/” -f5)


          print “
                    insert into ${TABLE}
                    (
                              user_name,
                              user_description
                    )
                    values
                    (
                         “${Item1}”,
                         “${Item5}”
                    );”


# Commit every 10 records – COUNT ends with a "0"
[[$ {COUNT} == + ([0-9]) 0]] & & print "commit;"
          done
          print “commit;” # Issue a commit after the last insert


          print “select * from ${TABLE};”
          print “drop table ${TABLE};”
} / sqlplus -s scott/tiger


У своїх скриптах оболонки я звичайно віддаю перевагу відключати автоматичну фіксацію (autocommit) і брати на себе відповідальність за фіксування, тим самим я можу керувати частотою. Зверніть увагу, що змінні оболонки Item1 і Item5 укладені в одиночні лапки в SQL-пропозиції вставки, оскільки вони є рядками. Не укладайте лапки числа!


Остерігайтеся символів одиночних лапок, що містяться у вихідних даних. Вони стануть причиною збоїв SQL-пропозицій, якщо тільки ви не відключите (escape) або видаліть їх.


Збереження траси процесу


Хоча я вже дуже задоволений, реалізувавши наведений вище код одноразового інтерфейсу, це всього лише початок. Основна проблема полягає в тому, що цей код не перевіряє, що Oracle сказав про всі ті SQL-пропозиції, які ми йому вкинули (threw). Однак це не важко подолати, оскільки вихідний лістинг SQL * Plus м ожет бути по каналу спрямований якомусь модулю, який і виконає необхідні перевірки.


Витончена хитрість, вживана в деяких ситуаціях (наприклад, в налагодженні), полягає в тому, що весь SQL * Plus-івський вхід (input) і вихід (output) поміщати у файл. Спробуйте замінити команду "} / sqlplus -S scott / tiger "(останній рядок в коді попереднього прикладу) на"} 2 & 1 / tee-a / tmp / ora.txt / sqlplus-s scott / tiger 2 & 1 / tee-a / tmp / ora.txt ".


Оскільки це досить тонка робота, я вважаю за краще замінити всі рядки "sqlplus-s scott / tiger" в тілі мого коду на псевдонім (alias), що дозволить мені використовувати механізм "debug oracle" (oracle-налагодження), який я можу активізувати, щоб записати введення / висновок (IO) Oracle. Для того щоб зробити це, треба в початок коду мого Oracle-скрипта оболонки включити наступне:



#!/usr/bin/ksh
typeset-irx TRUE = 0 # моє логічне "true" – код повернення
typeset-irx FALSE = 1 # моє логічне "false" – код повернення
typeset-r DEBUG = $ {TRUE} # Якщо DEBUG ON, можна поміняти на FALSE


if (( ${DEBUG} == ${TRUE} ))
then # Режим налагодження, все введення / висновок Oracle зберігається у файлі
          alias To_Oracle=”tee -a /tmp/ora.txt /
                    sqlplus -s scott/tiger 2&1 /
                    tee -a /tmp/ora.txt “
else # Звичайний режим, введення / висновок Oracle не записується
          alias To_Oracle=”sqlplus -s scott/tiger”
fi


Коль скоро псевдонім був визначений, я можу використовувати аліас To_Oracle замість рядка "sqlplus-s scott / tiger" в тілі мого коду, наприклад:



print “select * from dual;” / To_Oracle


Швидкий контроль помилок


Якщо SQL * Plus стикається з помилкою, він зазвичай видає повідомлення про її причини, яке починається з префікса ORA, ERROR або (останнім часом) SP2 і коду помилки. Озброєний цим знанням, я можу перевірити, чи всі взаємодії Oracle коректно працюють, просто переглядаючи вихідний лістинг на предмет наявності префіксів повідомлень про помилки, наприклад:



if print “
          create table ${TABLE}
          (
                    user_name varchar2(16),
                    user_description varchar2(64)
          );” /
     sqlplus -s scott/tiger /
     ! grep -qiE “ora/error/sp2”
then print “Table ${TABLE} created”
else print “An error was detected when creating table ${TABLE}”
fi


Зауважте, що в наведеному вище прикладі команда grep поверне true (істина), якщо в лістингу будуть знайдені один або більшу кількість префіксів помилкових повідомлень (в будь-якому поєднанні). Використовуючи знак вигуки (!), я заперечую у зверненнях з UNIX філософію "innocent until proven guilty" ("невинний, поки не доведена вина"). Необхідна гарантія, що в очікуваному лістингу немає префіксів повідомлень про помилки, інакше попереду вас чекає шторм.
Ще раз повторю, що я віддаю перевагу визначати псевдонім для запиту через SQL * Plus, але, щоб зробити це навіть більш симпатичним, може використовуватися функція, яка бере SQL як аргумент:



alias To_Oracle_OK = "sqlplus-s scott / tiger 2 & 1 /! grep-qiE" ora/error/sp2 ""


Код тепер виглядає наступним чином:



if print “
          create table ${TABLE}
          (
                    user_name varchar2(16),
                    user_description varchar2(64)
          );” / To_Oracle_OK
then print “Table ${TABLE} created”
else print “An error was detected when creating table ${TABLE}”
fi


Проблема ВЕЛИКОГО "commit"


Коли закінчується (terminate) сесія SQL * Plus, всі незафіксовані (uncommitted) транзакції або втрачаються (lost), або фіксуються (committed) – залежно від вашої установки. При використанні способу, який я тільки що навів, це викликає деякі труднощі у випадку, коли ви хочете без завершення поточної сесії SQL * Plus перевірити, як протікають події. [Прім.редактора: автор, мабуть, має на увазі термінальну (екранну) UNIX-сесію SQL * Plus, яка дійсно закривається, коли користувач розриває з'єднання з ОС.] Для протидії цій проблемі я породжують сесію SQL * Plus як сопроцесс (Co-process) та взаємодію з ним, використовуючи команди оболонки print-p і read-p. Наприклад, ініціюйте сесію SQL * Plus наступною командою:



sqlplus -s scott/tiger /&


Тепер спрямуємо дві команди до сопроцессу:



print -p “select * from dual;”
print -p “exit”


Здається, що нічого особливого не сталося, але наступний код:



while read -p LINE
do
          print – ${LINE}
done


поверне SQL * Plus-лістинг:


D

X


Зауваження: UNIX також повідомить, що сопроцесс завершений.


На жаль, команда read-p буде висіти (hang), якщо немає ніякого вихідного лістингу для видачі, або ж поки не завершиться вся видача вихідного лістингу. Це може також статися, якщо ви занадто швидко намагаєтеся схопити (grab) вихідний лістинг, в той час як Oracle все ще роздумує. Однак цей метод дає нагороду програмісту, оскільки здатний реалізувати повну комунікацію з Oracle через єдину вцілілу сесію SQL * Plus.


Для того, щоб уберегти мої програми від зависання команди read, розміщую у потік вихідного лістингу маркер (наприклад, використовуючи команду SQL * Plus "prompt") як вимога деякої роботи. Тим самим я гарантований, що код не проходить за маркер. Розміщення маркера також дає системі час, потрібний для запобігання "занадто швидкого" ("too quick") зависання, про який згадувалося раніше.



sqlplus-s scott / tiger / & # Старт сопроцесса sqlplus


print-p "select * from dual;" # SQL-звернення до сопросессу (sqlplus)
print-p "prompt marker1" # Установка маркера в лістингу


while read-p LINE # Читання всіх рядків з сопроцесса
do
[["$ {LINE}" == "marker1"]] & & break # Розрив циклу, якщо прочитаний маркер
print – $ {LINE} # Видача лістингу, згенерованого SQL
done
[["$ {LINE}" == "marker1"]] & & break # Розрив циклу, якщо прочитаний маркер
print – $ {LINE} # Видача лістингу, згенерованого SQL
done


У новіших версіях Korn-оболонки команда read має аргумент time-out.


PL/SQL


У прийомах, які описані в цій статті, PL / SQL може використовуватися нарівні з SQL. Наприклад:



sqlplus-s scott / tiger / & # Старт sqlplus як сопроцесса


print -p “begin
               null;
end; "# Визначення анонімного блоку PL / SQL
print-p "/" # Виконання блокаPL / SQL
print-p "exit" # Завершення сопроцесса


while read-p LINE # Отримання лістингу сопроцесса do
               print – ${LINE}
done
produces the output:


PL/SQL procedure successfully completed.


Висновок


Перевага використання оболонкой Oracle-скриптів полягає в тому, що можна застосувати повний спектр UNIX-інструментів з даними Oracle. Враховуючи, що Oracle-інтерфейс досить простий, підвищення продуктивності, отримане розробником скриптів за рахунок використання UNIX для управління даними, може бути досить істотним. І завжди слід пам'ятати, що є більш ніж один спосіб виконати задумане.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*