ПРИЛОЖЕНИЕ B ---------------------------------------------------------------- ПРИМЕРЫ ПРОГРАММ В этом приложении приведено несколько типовых программ PL/SQL, чтобы помочь вам писать ваши собственные программы. Эти примеры иллюстрируют следующие важные концепции и возможности PL/SQL: * циклы FOR * курсоры * правила сферы * пакетная обработка транзакций * встроенный PL/SQL * вызов хранимой процедуры Примеры программ B-1 ---------------- Примеры программ, приведенные в этом приложении, а также множество других примеров, разбросанных по этому руководству, поставляются с дистрибуцией. Такие примеры сопровождаются комментарием вида -- доступен на диске в файле имя_файла Следующая таблица показывает имена этих файлов и места в данном документе, где приводится их текст. Однако точные имена и местоположения файлов зависят от системы. Ссылка в руководстве Имя файла ----------------------------------------- Глава 1, стр. 2 EXAMP1 Глава 1, стр. 7 EXAMP2 Глава 1, стр. 8 EXAMP3 Глава 2, стр. 25 EXAMP4 Глава 4, стр. 21 EXAMP5 Глава 4, стр. 22 EXAMP6 Глава 4, стр. 27 EXAMP7 Глава 4, стр. 29 EXAMP8 Глава 8, стр. 6 EXAMP9 Глава 8, стр. 9 EXAMP10 Глава 9, стр. 16 EXAMP11 Глава 9, стр. 47 EXAMP12 Глава 9, стр. 76 EXAMP13 Глава 9, стр. 103 EXAMP14 Приложение B, стр. 11 SAMPLE1 Приложение B, стр. 13 SAMPLE2 Приложение B, стр. 14 SAMPLE3 Приложение B, стр. 17 SAMPLE4 Приложение B, стр. 20 SAMPLE5 Приложение B, стр. 25 SAMPLE6 Некоторые примеры запускаются интерактивно из SQL*Plus; другие запускаются из программ Pro*C. Вы можете экспериментировать с этими примерами под любым учетным именем. Например, примеры на Pro*C ожидают, что вы будете использовать имя SCOTT/TIGER. B-2 Руководство пользователя и справочник по PL/SQL Прежде чем пытаться выполнять примеры, вы должны создать несколько таблиц в базе данных, а затем загрузить эти таблицы данными. Это осуществляется запуском двух скриптов SQL*Plus, EXAMPBLD и EXAMPLOD, поставляемых с PL/SQL и находящихся в дистрибуции PL/SQL. Относительно точного местоположения этих скриптов справьтесь в руководстве по инсталляции для вашей системы. Создание таблиц --------------- Ниже приведен листинг скрипта SQL*Plus с именем EXAMPBLD. Этот скрипт содержит предложения CREATE, которые необходимы для создания таблиц, используемых во всех примерах настоящего руководства. Чтобы выполнить этот скрипт, вызовите SQL*Plus, а затем выдайте следующую команду: SQL> START EXAMPBLD Скрипт EXAMPBLD set compatibility V6 / drop table accounts / create table accounts( account_id number(4) not null, bal number(11,2)) / create unique index accounts_index on accounts (account_id) / drop table action / create table action( account_id number(4) not null, oper_type char(1) not null, new_value number(11,2), status char(45), time_tag date not null) / drop table bins / create table bins( bin_num number(2) not null, part_num number(4), amt_in_bin number(4)) / drop table data_table / Примеры программ B-3 create table data_table( exper_num number(2), n1 number(5), n2 number(5), n3 number(5)) / drop table emp / create table emp( empno number(4) not null, ename char(10), job char(9), mgr number(4), hiredate date, sal number(7,2), comm number(7,2), deptno number(2)) / drop table inventory / create table inventory( prod_id number(5) not null, product char(15), quantity number(5)) / drop table journal / create table journal( account_id number(4) not null, action char(45) not null, amount number(11,2), date_tag date not null) / drop table num1_tab / create table num1_tab( sequence number(3) not null, num number(4)) / drop table num2_tab / create table num2_tab( sequence number(3) not null, num number(4)) / drop table purchase_record / B-4 Руководство пользователя и справочник по PL/SQL create table purchase_record( mesg char(45), purch_date date) / drop table ratio / create table ratio( sample_id number(3) not null, ratio number) / drop table result_table / create table result_table( sample_id number(3) not null, x number, y number) / drop table sum_tab / create table sum_tab( sequence number(3) not null, sum number(5)) / drop table temp / create table temp( num_col1 number(9,4), num_col2 number(9,4), char_col char(55)) / create or replace package personnel as type charArrayTyp is table of varchar2(10) index by binary_integer; type numArrayTyp is table of float index by binary_integer; procedure get_employees( dept_number in integer, batch_size in integer, found in out integer, done_fetch out integer, emp_name out charArrayTyp, job_title out charArrayTyp, salary out numArrayTyp); end personnel; / Примеры программ B-5 create or replace package body personnel as cursor get_emp (dept_number integer) is select ename, job, sal from emp where deptno = dept_number; procedure get_employees( dept_number in integer, batch_size in integer, found in out integer, done_fetch out integer, emp_name out charArrayTyp, job_title out charArrayTyp, salary out numArrayTyp) is begin if not get_emp%isopen then open get_emp(dept_number); end if; done_fetch := 0; found := 0; for i in 1..batch_size loop fetch get_emp into emp_name(i), job_title(i), salary(i); if get_emp%notfound then close get_emp; done_fetch := 1; exit; else found := found + 1; end if; end loop; end get_employees; end personnel; / Загрузка данных --------------- Ниже приведен листинг скрипта SQL*Plus с именем EXAMPLOD. Этот файл содержит предложения INSERT, которые необходимы для загрузки (или сброса) таблиц, используемых во всех примерах настоящего руководства. Чтобы выполнить этот скрипт, вызовите SQL*Plus под тем же учетным именем, под которым вы выполняли EXAMPBLD, а затем выдайте следующую команду: SQL> START EXAMPLOD Скрипт EXAMPLOD delete from accounts / insert into accounts values (1,1000.00) / insert into accounts values (2,2000.00) / B-6 Руководство пользователя и справочник по PL/SQL insert into accounts values (3,1500.00) / insert into accounts values (4,6500.00) / insert into accounts values (5,500.00) / delete from action / insert into action values (3,'u',599,null,sysdate) / insert into action values (6,'i',20099,null, sysdate) / insert into action values (5,'d',null,null, sysdate) / insert into action values (7,'u',1599,null, sysdate) / insert into action values (1,'i',399,null,sysdate) / insert into action values (9,'d',null,null,sysdate) / insert into action values (10,'x',null,null,sysdate) / delete from bins / insert into bins values (1, 5469, 650) / insert into bins values (2, 7243, 450) / insert into bins values (3, 5469, 120) / insert into bins values (4, 5469, 300) / insert into bins values (5, 6085, 415) / insert into bins values (6, 5469, 280) / insert into bins values (7, 8159, 619) / delete from data_table / Примеры программ B-7 insert into data_table values (1, 10, 167, 17) / insert into data_table values (1, 16, 223, 35) / insert into data_table values (2, 34, 547, 2) / insert into data_table values (3, 23, 318, 11) / insert into data_table values (1, 17, 266, 15) / insert into data_table values (1, 20, 117, 9) / delete from emp / insert into emp values (7369,'SMITH','CLERK',7902,TO_DATE('12-17-80','MM-DD-YY'), 800,NULL,20) / insert into emp values (7499,'ALLEN','SALESMAN',7698,TO_DATE('02-20-81', 'MM-DD-YY'),1600,300,30) / insert into emp values (7521,'WARD','SALESMAN',7698,TO_DATE('02-22-81', 'MM-DD-YY'),1250,500,30) / insert into emp values (7566,'JONES','MANAGER',7839,TO_DATE('04-02-81', 'MM-DD-YY'),2975,NULL,20) / insert into emp values (7654,'MARTIN','SALESMAN',7698,TO_DATE('09-28-81', 'MM-DD-YY'),1250,1400,30) / insert into emp values (7698,'BLAKE','MANAGER',7839,TO_DATE('05-1-81', 'MM-DD-YY'),2850,NULL,30) / B-8 Руководство пользователя и справочник по PL/SQL insert into emp values (7782,'CLARK','MANAGER',7839,TO_DATE('06-9-81', 'MM-DD-YY'),2450,NULL,10) / insert into emp values (7788,'SCOTT','ANALYST',7566,SYSDATE-85,3000,NULL,20) / insert into emp values (7839,'KING','PRESIDENT',NULL,TO_DATE('11-17-81', 'MM-DD-YY'),5000,NULL,10) / insert into emp values (7844,'TURNER','SALESMAN',7698,TO_DATE('09-8-81', 'MM-DD-YY'),1500,0,30) / insert into emp values (7876,'ADAMS','CLERK',7788,SYSDATE-51,1100,NULL,20) / insert into emp values (7900,'JAMES','CLERK',7698,TO_DATE('12-3-81', 'MM-DD-YY'),950,NULL,30) / insert into emp values (7902,'FORD','ANALYST',7566,TO_DATE('12-3-81', 'MM-DD-YY'),3000,NULL,20) / insert into emp values (7934,'MILLER','CLERK',7782,TO_DATE('01-23-82', 'MM-DD-YY'),1300,NULL,10) / delete from inventory / insert into inventory values (1234, 'TENNIS RACQUET', 3) / insert into inventory values (8159, 'GOLF CLUB', 4) / insert into inventory values (2741, 'SOCCER BALL', 2) / delete from journal / delete from num1_tab / insert into num1_tab values (1, 5) / Примеры программ B-9 insert into num1_tab values (2, 7) / insert into num1_tab values (3, 4) / insert into num1_tab values (4, 9) / delete from num2_tab / insert into num2_tab values (1, 15) / insert into num2_tab values (2, 19) / insert into num2_tab values (3, 27) / delete from purchase_record / delete from ratio / delete from result_table / insert into result_table values (130, 70, 87) / insert into result_table values (131, 77, 194) / insert into result_table values (132, 73, 0) / insert into result_table values (133, 81, 98) / delete from sum_tab / delete from temp / commit / B-10 Руководство пользователя и справочник по PL/SQL ---------------- Пример 1. Цикл FOR В следующем примере простой цикл FOR используется для вставки десяти строк в таблицу. Вставляются значения индекса цикла, переменной-счетчика и одной из двух символьных строк, в зависимости от четности или нечетности текущего значения индексной переменной цикла. Входная таблица Отсутствует. Блок PL/SQL -- доступен на диске в файле SAMPLE1 DECLARE x NUMBER := 100; BEGIN FOR i IN 1..10 LOOP IF MOD(i,2) = 0 THEN -- i is even INSERT INTO temp VALUES (i, x, 'i is even'); ELSE INSERT INTO temp VALUES (i, x, 'i is odd'); END IF; x := x + 100; END LOOP; COMMIT; END; Результирующая таблица SQL> SELECT * FROM temp ORDER BY col1; COL1 COL2 CHAR_COL ----- ------- --------- 1 100 i is odd 2 200 i is even 3 300 i is odd 4 400 i is even 5 500 i is odd 6 600 i is even 7 700 i is odd 8 800 i is even 9 900 i is odd 10 1000 i is even 10 records selected. Примеры программ B-11 ---------------- Пример 2. Курсоры В следующем примере курсор используется для извлечения пяти самых высокооплачиваемых сотрудников из таблицы emp. Входная таблица SQL> SELECT ename, empno, sal FROM emp ORDER BY sal DESC; ENAME EMPNO SAL ---------- ----------- ------- KING 7839 5000 SCOTT 7788 3000 FORD 7902 3000 JONES 7566 2975 BLAKE 7698 2850 CLARK 7782 2450 ALLEN 7499 1600 TURNER 7844 1500 MILLER 7934 1300 WARD 7521 1250 MARTIN 7654 1250 ADAMS 7876 1100 JAMES 7900 950 SMITH 7369 800 14 records selected. B-12 Руководство пользователя и справочник по PL/SQL Блок PL/SQL --доступен на диске в файле SAMPLE2 DECLARE CURSOR c1 is SELECT ename, empno, sal FROM emp ORDER BY sal DESC; -- start with highest paid employee my_ename CHAR(10); my_empno NUMBER(4); my_sal NUMBER(7,2); BEGIN OPEN c1; FOR i IN 1..5 LOOP FETCH c1 INTO my_ename, my_empno, my_sal; EXIT WHEN c1%NOTFOUND; /* in case the number requested is more than the total number of employees */ INSERT INTO temp VALUES (my_sal, my_empno, my_ename); COMMIT; END LOOP; CLOSE c1; END; Результирующая таблица SQL> SELECT * FROM temp ORDER BY col1 DESC; COL1 COL2 CHAR_COL ----- ------- --------- 5000 7839 KING 3000 7902 FORD 3000 7788 SCOTT 2975 7566 JONES 2850 7698 BLAKE Примеры программ B-13 ---------------- Пример 3. Правила сферы Следующий пример иллюстрирует структуру блоков и правила сферы. Внешний блок объявляет две переменные с именами x и counter, и четыре раза выполняет цикл. Подблок внутри этого цикла также объявляет переменную с именем x. Значения, вставляемые в таблицу TEMP, показывают, что эти две переменные x действительно различны. Входная таблица Не используется. Блок PL/SQL -- доступен на диске в файле SAMPLE3 DECLARE x NUMBER := 0; counter NUMBER := 0; BEGIN FOR i IN 1..4 LOOP x := x + 1000; counter := counter + 1; INSERT INTO temp VALUES (x, counter, 'outer loop'); /* start an inner block */ DECLARE x NUMBER := 0; -- this is a local version of x BEGIN FOR i IN 1..4 LOOP x := x + 1; -- this increments the local x counter := counter + 1; INSERT INTO temp VALUES(x,counter,'inner loop'); END LOOP; END; END LOOP; COMMIT; END; B-14 Руководство пользователя и справочник по PL/SQL Результирующая таблица SQL> SELECT * FROM temp ORDER BY col2; COL1 COL2 CHAR_COL ------- -------- ------------- 1000 1 outer loop 1 2 inner loop 2 3 inner loop 3 4 inner loop 4 5 inner loop 2000 6 outer loop 1 7 inner loop 2 8 inner loop 3 9 inner loop 4 10 inner loop 3000 11 outer loop 1 12 inner loop 2 13 inner loop 3 14 inner loop 4 15 inner loop 4000 16 outer loop 1 17 inner loop 2 18 inner loop 3 19 inner loop 4 20 inner loop 20 records selected. Примеры программ B-15 ---------------- Пример 4. Пакетная обработка транзакций В следующем примере таблица accounts модифицируется согласно инструкциям, содержащимся в таблице action. Каждая строка в таблице action содержит: номер счета, требуемое действие (I, U или D для вставки, обновления или удаления), количество, на которое следует изменить счет (если действие не является удалением счета), и отметку времени, которая служит для упорядочения транзакций. При выполнении вставки, если счет уже существует, вместо вставки осуществляется обновление счета. При обновлении, если счет не существует, он создается. При удалении, если счет не существует, никаких действий не выполняется. Входные таблицы SQL> SELECT * FROM accounts ORDER BY account_id; ACCOUNT_ID BAL ---------- --------- 1 1000 2 2000 3 1500 4 6500 5 500 SQL> SELECT * FROM action ORDER BY time_tag; ACCOUNT_ID O NEW_VALUE STATUS TIME_TAG ---------- - --------- ------------------------- --------- 3 u 599 18-NOV-88 6 i 20099 18-NOV-88 5 d 18-NOV-88 7 u 1599 18-NOV-88 1 i 399 18-NOV-88 9 d 18-NOV-88 10 x 18-NOV-88 7 records selected. B-16 Руководство пользователя и справочник по PL/SQL Блок PL/SQL -- доступен на диске в файле SAMPLE4 DECLARE CURSOR c1 IS SELECT account_id, oper_type, new_value FROM action ORDER BY time_tag FOR UPDATE OF status; BEGIN FOR acct IN c1 LOOP -- process each row one at a time acct.oper_type := upper(acct.oper_type); /*----------------------------------------* * Process an UPDATE. If the account to * * be updated doesn't exist, create a new * * account. * *----------------------------------------*/ IF acct.oper_type = 'U' THEN UPDATE accounts SET bal = acct.new_value WHERE account_id = acct.account_id; IF SQL%NOTFOUND THEN -- account didn't exist. -- Create it. INSERT INTO accounts VALUES (acct.account_id, acct.new_value); UPDATE action SET status = 'Update: ID not found. Value inserted.' WHERE CURRENT OF c1; ELSE UPDATE action SET status = 'Update: Success.' WHERE CURRENT OF c1; END IF; /*--------------------------------------------* * Process an INSERT. If the account already * * exists, do an update of the account * * instead. * *--------------------------------------------*/ ELSIF acct.oper_type = 'I' THEN BEGIN INSERT INTO accounts VALUES (acct.account_id, acct.new_value); UPDATE action set status = 'Insert: Success.' WHERE CURRENT OF c1; Примеры программ B-17 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN -- account already -- exists UPDATE accounts SET bal = acct.new_value WHERE account_id = acct.account_id; UPDATE action SET status = 'Insert: Acct exists. Updated instead.' WHERE CURRENT OF c1; END; /*--------------------------------------------* * Process a DELETE. If the account doesn't * * exist, set the status field to say that * * the account wasn't found. * *--------------------------------------------*/ ELSIF acct.oper_type = 'D' THEN DELETE FROM accounts WHERE account_id = acct.account_id; IF SQL%NOTFOUND THEN -- account didn't exist. UPDATE action SET status = 'Delete: ID not found.' WHERE CURRENT OF c1; ELSE UPDATE action SET status = 'Delete: Success.' WHERE CURRENT OF c1; END IF; /*--------------------------------------------* * The requested operation is invalid. * *--------------------------------------------*/ ELSE -- oper_type is invalid UPDATE action SET status = 'Invalid operation. No action taken.' WHERE CURRENT OF c1; END IF; END LOOP; COMMIT; END; B-18 Руководство пользователя и справочник по PL/SQL Результирующие таблицы SQL> SELECT * FROM accounts ORDER BY account_id; ACCOUNT_ID BAL ---------- --------- 1 399 2 2000 3 599 4 6500 6 20099 7 1599 6 records selected. SQL> SELECT * FROM action ORDER BY time_tag; ACCOUNT_ID O NEW_VALUE STATUS TIME_TAG ---------- - --------- ------------------------- --------- 3 u 599 Update: Success. 18-NOV-88 6 i 20099 Insert: Success. 18-NOV-88 5 d Delete: Success. 18-NOV-88 7 u 1599 Update: ID not found. 18-NOV-88 Value inserted. 1 i 399 Insert: Acct exists. 18-NOV-88 Updated instead. 9 d Delete: ID not found. 18-NOV-88 10 x Invalid operation. 18-NOV-88 No action taken. 7 records selected. Примеры программ B-19 ---------------- Пример 5. Встроенный PL/SQL Следующий пример иллюстрирует, как можно встроить PL/SQL в хост-язык высокого уровня, такой как C, и демонстрирует выполнение банковской дебиторской транзакции. Входная таблица SQL> SELECT * FROM accounts ORDER BY account_id; ACCOUNT_ID BAL ---------- --------- 1 1000 2 2000 3 1500 4 6500 5 500 Блок PL/SQL в программе на языке C /* доступен на диске в файле SAMPLE5 */ #includechar buf[20]; EXEC SQL BEGIN DECLARE SECTION; int acct; double debit; double new_bal; VARCHAR status[65]; VARCHAR uid[20]; VARCHAR pwd[20]; EXEC SQL END DECLARE SECTION; EXEC SQL INCLUDE SQLCA; main() { extern double atof(); strcpy (uid.arr,"scott"); uid.len=strlen(uid.arr); strcpy (pwd.arr,"tiger"); pwd.len=strlen(pwd.arr); printf("\n\n\tEmbedded PL/SQL Debit Transaction Demo\n\n"); printf("Trying to connect..."); B-20 Руководство пользователя и справочник по PL/SQL EXEC SQL WHENEVER SQLERROR GOTO errprint; EXEC SQL CONNECT :uid IDENTIFIED BY :pwd; printf(" connected.\n"); for (;;) /* Loop infinitely */ { printf("\n** Debit which account number? (-1 to end) "); gets(buf); acct = atoi(buf); if (acct == -1) { EXEC SQL COMMIT WORK RELEASE; /* log off ORACLE first */ exit(0); /* then exit program */ } printf(" What is the debit amount? "); gets(buf); debit = atof(buf); /* ---------------------------------- */ /* ----- Begin the PL/SQL block ----- */ /* ---------------------------------- */ EXEC SQL EXECUTE DECLARE insufficient_funds EXCEPTION; old_bal NUMBER; min_bal NUMBER := 500; BEGIN SELECT bal INTO old_bal FROM accounts WHERE account_id = :acct; -- If the account doesn't exist, the NO_DATA_FOUND -- exception will be automatically raised. :new_bal := old_bal - :debit; IF :new_bal >= min_bal THEN UPDATE accounts SET bal = :new_bal WHERE account_id = :acct; INSERT INTO journal VALUES (:acct, 'Debit', :debit, sysdate); :status := 'Transaction completed.'; ELSE RAISE insufficient_funds; END IF; COMMIT; Примеры программ B-21 EXCEPTION WHEN NO_DATA_FOUND THEN :status := 'Account not found.'; :new_bal := -1; WHEN insufficient_funds THEN :status := 'Insufficient funds.'; :new_bal := old_bal; WHEN OTHERS THEN ROLLBACK; :status := 'Error: ' || SQLERRM(SQLCODE); :new_bal := -1; END; END-EXEC; /* -------------------------------- */ /* ----- End the PL/SQL block ----- */ /* -------------------------------- */ status.arr[status.len] = '\0'; /* null terminate the string */ printf("\n\n Status: %s\n", status.arr); if (new_bal >= 0) printf(" Balance is now: $%.2f\n", new_bal); } /* End of loop */ errprint: EXEC SQL WHENEVER SQLERROR CONTINUE; printf("\n\n>>>>> Error during execution:\n"); printf("%s\n",sqlca.sqlerrm.sqlerrmc); EXEC SQL ROLLBACK RELEASE; exit(1); } Интерактивная сессия Embedded PL/SQL Debit Transaction Demo Trying to connect... connected. ** Debit which account number? (-1 to end) 1 What is the debit amount? 300 Status: Transaction completed. Balance is now: $700.00 ** Debit which account number? (-1 to end) 1 What is the debit amount? 900 B-22 Руководство пользователя и справочник по PL/SQL Status: Insufficient funds. Balance is now: $700.00 ** Debit which account number? (-1 to end) 2 What is the debit amount? 500 Status: Transaction completed. Balance is now: $1500.00 ** Debit which account number? (-1 to end) 2 What is the debit amount? 100 Status: Transaction completed. Balance is now: $1400.00 ** Debit which account number? (-1 to end) 99 What is the debit amount? 100 Status: Account not found. ** Debit which account number? (-1 to end) -1 Результирующие таблицы SQL> SELECT * FROM accounts ORDER BY account_id; ACCOUNT_ID BAL ---------- --------- 1 700 2 1400 3 1500 4 6500 5 500 SQL> SELECT * FROM journal ORDER BY date_tag; ACCOUNT_ID ACTION AMOUNT DATE_TAG ---------- --------------------------- --------- --------- 1 Debit 300 28-NOV-88 2 Debit 500 28-NOV-88 3 Debit 100 28-NOV-88 Примеры программ B-23 ---------------- Пример 6. Вызов хранимой процедуры Эта программа Pro*C соединяется с ORACLE, запрашивает у пользователя номер отдела, а затем вызывает хранимую процедуру с именем get_employees, находящуюся в пакете с именем personnel. Эта процедура объявляет три таблицы PL/SQL как формальные параметры OUT и извлекает в эти таблицы порцию данных о сотрудниках заданного отдела. Соответствующие фактические параметры являются хост-массивами. Когда процедура завершается, она автоматически присваивает все значения строк в таблицах PL/SQL соответствующим элементам в хост-массивах. Вызывающая программа обращается к процедуре повторно, распечатывая каждый раз полученную порцию данных, до тех пор, пока все данные не будут распечатаны. Входная таблица SQL> SELECT ename, empno, sal FROM emp ORDER BY sal DESC; ENAME EMPNO SAL ---------- ----------- ------- KING 7839 5000 SCOTT 7788 3000 FORD 7902 3000 JONES 7566 2975 BLAKE 7698 2850 CLARK 7782 2450 ALLEN 7499 1600 TURNER 7844 1500 MILLER 7934 1300 WARD 7521 1250 MARTIN 7654 1250 ADAMS 7876 1100 JAMES 7900 950 SMITH 7369 800 14 records selected. B-24 Руководство пользователя и справочник по PL/SQL Хранимая процедура /* доступна на диске в файле SAMPLE6 */ #include #include typedef char asciz; EXEC SQL BEGIN DECLARE SECTION; /* Define type for null-terminated strings. */ EXEC SQL TYPE asciz IS STRING(20); asciz username[20]; asciz password[20]; int dept_no; /* which department to query */ char emp_name[10][21]; char job[10][21]; float salary[10]; int done_flag; int array_size; int num_ret; /* number of rows returned */ int SQLCODE; EXEC SQL END DECLARE SECTION; EXEC SQL INCLUDE SQLCA; int print_rows(); /* produces program output */ int sqlerror(); /* handles unrecoverable errors */ main() { int i; /* Connect to ORACLE. */ strcpy(username, "SCOTT"); strcpy(password, "TIGER"); EXEC SQL WHENEVER SQLERROR DO sqlerror(); EXEC SQL CONNECT :username IDENTIFIED BY :password; printf("\nConnected to ORACLE as user: %s\n\n", username); printf("Enter department number: "); scanf("%d", &dept_no); fflush(stdin); Примеры программ B-25 /* Print column headers. */ printf("\n\n"); printf("%-10.10s%-10.10s%s\n", "Employee", "Job", "Salary"); printf("%-10.10s%-10.10s%s\n", "--------", "---", "------"); /* Set the array size. */ array_size = 10; done_flag = 0; num_ret = 0; /* Array fetch loop - ends when NOT FOUND becomes true. */ for (;;) { EXEC SQL EXECUTE BEGIN personnel.get_employees (:dept_no, :array_size, :num_ret, :done_flag, :emp_name, :job, :salary); END; END-EXEC; print_rows(num_ret); if (done_flag) break; } /* Disconnect from ORACLE. */ EXEC SQL COMMIT WORK RELEASE; exit(0); } print_rows(n) int n; { int i; if (n == 0) { printf("No rows retrieved.\n"); return; } for (i = 0; i < n; i++) printf("%10.10s%10.10s%6.2f\n", emp_name[i], job[i], salary[i]); } B-26 Руководство пользователя и справочник по PL/SQL sqlerror() { EXEC SQL WHENEVER SQLERROR CONTINUE; printf("\nORACLE error detected:"); printf("\n% .70s \n", sqlca.sqlerrm.sqlerrmc); EXEC SQL ROLLBACK WORK RELEASE; exit(1); } Интерактивная сессия Connected to ORACLE as user: SCOTT Enter department number: 20 Employee Job Salary -------- -------- ------ SMITH CLERK 800.00 JONES MANAGER 2975.00 SCOTT ANALYST 3000.00 ADAMS CLERK 1100.00 FORD ANALYST 3000.00