ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.






                        ORACLE



                       PRO*C:

                       РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ







                        ВЕРСИЯ 1.1

                   10 АПРЕЛЯ 1987 ГОДА














               ORACLE PART NO. 3504-V1.1



                            -1-


ПРЕДИСЛОВИЕ

НАЗНАЧЕНИЕ

Это руководство  предоставляет   пользователю    инструкцию
по  написанию прикладных программ  для   манипулирования  и
доступа к данным в ORACLE RDBMS.

ORACLE предоставляет проблемным программистам два программ-
ных интерфейса.  Первым,  и более эффективным для развиваю-
щихся прикладных  программ является прекомпиляторный интер-
фейс. С    помощью  прекомпиляторного  интерфейса  возможно
написание прикладных   программ  на  языках высокого уровня
(таких, как FORTRAN, PASCAL, C, PL1 или COBOL), которые со-
держат встроенные операторы, написанные на языке SQL.  Пре-
компилятор транслирует операторы SQL,  встроенные  в  такую
программу, в  коды языка более высокого уровня, чтобы можно
было затем их скомпилировать и связать  с  соответствующими
библиотеками рабочих программ в выполняемый код.

Использование прекомпилятора PRO*C дает возможность  прик-
ладным программам  сочетать  наиболее  подходящие средства
как C,так и SQL в одной программе.

Второй интерфейс,называемый  ORACLE  CALL  интерфейс (ранее
известный как интерфейс высокого уровня или HLI), также до-
пускает применение языков  высокого уровня  для  доступа  к
данным в   системе  управления   реляционной  базой  данных
ORACLE. Программы, которые используют  ORACLE CALL   интер-
фейс, могут непосредственно вызывать шаблоны ORACLE, содер-
жащиеся в свойственных для выбранного языка библиотеках ра-
бочих программ.

Оба этих интерфейса повышают процесс  развития  прикладных
программ,которые будут  использоваться  для  манипуляции и
определения данных в базе данных ORACLE.


                            -2-


АУДИТОРИЯ

Это руководство   предназначено   разработчику   прикладных
программ,использующему один из интерфейсов высокого  уровня
для связи  с ORACLE.Читатели этого руководства должны  быть
хорошо знакомы :

    с программированием на языке C
    с доступом к данным в ORACLE RDBMS
    c языком SQL


СОДЕРЖАНИЕ РУКОВОДСТВА

Это руководство разделено на две части:  Часть1    содержит
информацию по использованию прекомпиляторного  интерфейса С
и  Часть2   предоставляет   документацию  по     интерфейсу
ORACLE CALL(OCI).

Содержание руководства следующее:

1.ВВЕДЕНИЕ В PRO*C.  Эта глава является общим  введением  в
PRO*C. В ней обсуждается, почему  необходимо   использовать
PRO*C, типы операторов,  определяемых в программах на PRO*C
и пример команды PCC.

2.ЭЛЕМЕНТЫ ПРОГРАММЫ НА PRO*C.  В этой главе рассматривает-
ся объявление переменных, используемых   в   программе   на
PRO*C. Рассматриваются  обязательные разделы пролога   при-
кладной программы и содержится несколько образцов  коротких
кодов для входа и выхода в ORACLE  и  коротенькие  програм-
мки для создания таблиц или внесения записей.

3.ЗАПРОСЫ.  Эта глава вводит понятие  курсоров,используемых
для возврата  результатов запросов. После знакомства с раз-
личными курсорными командами будут  приведены образцы  двух
программ.

4.СОХРАНЕНИЕ И ОТКАТ РЕЗУЛЬТАТОВ РАБОТЫ.   В этой главе оп-
ределяется транзакция или логическая единица работы, в  ко-
торой объединено несколько операторов  SQL как целое.  Про-
граммист имеет  возможность  написать  программу так,   что
сможет контролировать, когда транзакция программы сохраняет
(фиксирует в базе данных)  либо откатывает (стирает из базы
данных) результаты работы.

5.ОБНАРУЖЕНИЕ ОШИБОК И ВОССТАНОВЛЕНИЕ.   В этой  главе даны
рекомендации программистам по использованию  SQLСА и указа-
телей переменных с  целью  обнаружения  ошибок и выполнения
различных условий, таких  как пустое значение,  безусловное
удаление, отсутствие строки  возврата и переполнение данных
или усечение данных.


                            -3-


6.ДИНАМИЧЕСКИ ОПРЕДЕЛЯЕМЫЕ ОПЕРАТОРЫ.    Эта глава позволя-
ет продвинуться в технике  программирования, что   окажется
полезным при написании  особо  гибких  программ,  но потре-
бует большего  понимания  программистом  языков  С  и  SQL.
Программист, начинающий работать с PRO*C,  может пропустить
либо бегло прочитать эту главу.

7.ВЫЗОВ PRO*C (КОМАНДЫ РСС).   В этой главе описаны команды
РСС и их опции.

8.ВВЕДЕНИЕ В PRO*SQL.   В этой главе вводятся понятия, ис-
пользуемые при  написанни программ на PRO*SQL,  такие,  как
область данных     курсора,область     данных     регистра-
ции (logon), код возврата, типы параметров и структура про-
граммы.

9.ОПИСАНИЕ ОТДЕЛЬНЫХ ПРОГРАММНЫХ ВЫЗОВОВ (CALL).  Эта глава
знакомит с различными вызовами OCI. В каждом разделе,  зна-
комящем с различными вызовами, представлен  общий синтаксис
и дан пример на С. Вызовы рассматриваются в  порядке  появ-
ления, а не в  алфавитном  порядке. ( Заметим,  что  полный
список вызовов в алфавитном порядке  можно найти в приложе-
нии).

10.ТИПЫ ДАННЫХ.   В  главе рассматриваются как типы данных,
используемых в OCI и в ORACLE RDBMS,  так и преобразавания,
которые могут быть произведены над ними.

11.СТАРЫЕ ВАРИАНТЫ ВЫЗОВОВ PRO*SQL.   В  этой  главе кратко
приведены старые варианты вызовов,представленные в главе 2,
но включенные здесь для получения  более   полной  картины.
В разделах для   каждого  вызова   представлен  общий  син-
таксис, включено обсуждение применения  и  параметров вызо-
ва, а также дан  пример на С. Вызовы обсуждаются в  порядке
появления в программе,  а не в алфавитном порядке. (  Отме-
тим, что в приложении приведен  краткий список этих вызовов
в алфавитном порядке).

ПРИЛОЖЕНИЕ А: СООБЩЕНИЯ ОБ ОШИБКАХ.  Это приложение содер-
жит список сообщений об ошибках PRO*C.

ПРИЛОЖЕНИЕ B:  РУКОВОДСТВО ПО ПРОГРАММИРОВАНИЮ.  Это прило-
жение дает некоторые общие понятия, необходимые для написа-
ния программ на PRO*C.


                            -4-


ПРИЛОЖЕНИЕ C:   ЗАРЕЗЕРВИРОВАННЫЕ  СЛОВА.    Это приложение
содержит список   зарезервированных  слов, используемых   в
ORACLE RDBMS или в PRO*C, которые запрещены для использова-
ния в объектах ORACLE, идентифицируемых пользователем,  та-
ких, как таблицы, колонки, экранные формы.

ПРИЛОЖЕНИЕ D:  ОБРАЗЕЦ ПРОГРАММЫ НА PRO*C.   Это приложение
содержит список образцов программ, которые включаются в об-
ласть объектных  кодов,   распределенных  для пользователей
PRO*C.

ПРИЛОЖЕНИЕ F:  ПРИМЕР ПРОГРАММЫ НА  С,  ИСПОЛЬЗУЮЩЕЙ ИНТЕР-
ФЕЙС ORACLE  CALL.   Это приложение содержит дополнительную
программу на С,  которая дает  подсказку  пользователю  для
ввода (информации  о  служащих)  и добавляет записи о новых
служащих в базу данных после выполнения некоторого контроля.



РОДСТВЕННЫЕ ПУБЛИКАЦИИ

В процессе работы с этим руководством вы можете  обращаться
к текущим  публикациям  корпорации  ORACLE.Вы автоматически
получите перечень статей,  ссылающихся на закупленный  вами
продукт; вам нет необходимости получать все документы.  За-
мечания по  реализации  незамедлительно  корректируются   с
целью отображения последних изменений в продукте.

Публикации корпорации ORACLE:

Документация по ORACLE RDBMS:

*      ORACLE RDBMS releas notes ORACLE Part No. 3001
       (Замечания по реализации ORACLE RDBMS.)

*      ORACLE Overview and Introdaction to SQL ORACLE  Part
       No.3801
       ( Обзор ORACLE и введение в SQL.)

*      The ORACLE  Database  Administrator's  Guide  ORACLE
       PartONo.3601
       ( Руководство администратора базы данных ORACLE. )

*      ORACLE Utiliies User's Guide ORACLE Part No.3602
       (Утилиты ORACLE . Руководство пользователя.)

*      ORACLE Report  User's  Guide:   RPF/RPT  ORACLE Part
       No.3603
       ( Сообщения ORACLE. Руководство пользователя.)

*      ORACLE Error Messages and Codes ORACLE Part No.3605
       ( Сообшения об ошибках ORACLE. Руководство пользова-
         теля.)


                            -5-


Документация для    различных    прекомпиляторов    (PRO*C,
PRO*FORTRAN, PRO*COBOL, PRO*PLI):

*      PRO*ORACLE Releas Notes ORACLE Part No.3007
       ( Замечания по реализации Pro*ORACLE.)

*      PRO*C User's Guides ORACLE Part No.3004
       ( Pro*С: Руководство пользователя.)

*      PRO*COBOL User's Guides ORACLE Part No.3003
       ( Pro*Cobol: Руководство пользователя.)

*      PRO*FORTRAN User's Guides ORACLE Part No.3002
       ( Pro*Fortran: Руководство пользователя.)

*      PRO*PLI User's Guides ORACLE Part No.3005
       ( Pro*PLI: Руководство пользователя.)

*      PRO*PASCAL User's Guides ORACLE Part No.3006
       ( Pro*Pascal: Руководство пользователя.)

*      PRO*ADA User's Guides ORACLE Part No.3007
       ( Pro*Ada: Руководство пользователя.)

Документация по SQL*PLUS:

*      SQL*PLUS Releas Notes ORACLE Part No.3003
       ( Замечания по реализации SQL*Plus.)

*      SQL*PLUS User's Guide ORACLE Part No.3201
       (SQL*Plus. Руководство пользователя.)

*      A Quick Tour of SQL*PLUS Part No.3803
       ( Краткий обзор SQL*Plus.)

*      SQL*PLUS Quick Reference ORACLE Part No.3703
       ( Краткий справочник по SQL*Plus.)


                            -6-


Документация по SQL*FORMS:

*      SQL*FORMS Releas Notes ORACLE Part No.3004
       ( Замечания по реализации SQL*Forms.)

*      SQL*FORMS Opertor's Guide ORACLE Part No.3301
       ( SQL*Forms: Руководство оператора.)

*      SQL*FORMS Designer's Tutorial ORACLE Part No.3302
       ( SQL*Forms: Руководство разработчика.)

*      SQL*FORMS Designer's Reference ORACLE Part No.3304
       ( SQL*Forms: Справочная информация.)

*      SQL*FORMS User's Quick Reference ORACLE Part No.3704
       ( SQL*Forms: Краткий справочник пользователя.)

*      SQL*FORMS Designer's Quick Reference ORACLE Part No.
       3708
       ( SQL*Forms: Краткий справочник разработчика.)

*      A Quick Tour of SQL*FORMS Part No.3804
       ( Краткий обзор SQL*Forms.)

Документация по SQL*MENU:

*      SQL*MENU Releas Notes ORACLE Part No.3009
       ( Замечания по реализации SQL*Menu.)

*      SQL*MENU User's Guide ORACLE Part No.3303
       ( SQL*Menu: Руководство пользователя.)

Документация по EASY*SQL:

*      EASY*SQL Releas Notes ORACLE Part No.3002
       (Замечания по реализации EASY*SQL.)

*      Introduction to EASY*SQL ORACLE Part No.3810
       ( Введение в EASY*SQL.)

*      EASY*SQL User's Guide ORACLE Part No.3101
       (EASY*SQL: Руководство пользователя.)

*      A Quick Tour of EARSY*SQL Part No.3702
       (Краткий обзор EASY*SQL.)

*      EASY*SQL Reference Card ORACLE Part No.3802
       ( Перечень ссылок EASY*SQL.)


                            -7-


Документация по SQL*GRAPH:

*      SQL*GRAPH Releas Notes ORACLE Part No.3006
       (Замечания по реализации SQL*Graph.)

*      SQL*GRAPH User's Guide ORACLE Part No.3402
       (SQL*Graph: Руководство пользователя.)

*      A Quick Tour of SQL*GRAPH Part No.3806
       (Краткий обзор SQL*Graph.)

*      SQL*GRAPH Quick Reference ORACLE Part No.3706
       (SQL*Graph: Краткий справочник.)

Документация по SQL*CALC

*      Introduction to SQL*CALC for Lotus 1-2-3 Users
       ORACLE Part No.3809
       (Введение в SQL*Calc.)

*      SQL*CALC Releas Notes ORACLE Part No.3005
       (Замечания по реализации SQL*Calc.)

*      SQL*CALC User's Guide ORACLE Part No.3401
       (SQL*Calc:Руководство пользователя.)

*      A Quick Tour of SQL*CALC ORACLE Part No.3805
       ( Краткий обзор SQL*Calc.)

*      SQL*CALC Quick Reference ORACLE Part No.3705
       (SQL*Calc: Краткий справочник.)

Для каждой операционной системы, на  которой  поддерживается
ORACLE, предусмотрено также руководство по инсталяции и ру-
ководство пользователю.

*      ORACLE for DEC VAX/VMS Installation and User's Guide
       ORACLE Part No.1001
       ( Руководство пользователя по инсталяции ORACLE  для
         DEC VAX/VMS.)

*      ORACLE for IBM VM/SP Installation and User's Guide
       ORACLE Part No.1003
       ( Руководство пользователя по инсталяции ORACLE  для
         IBM VM/SP.)


                            -8-


СОГЛАШЕНИЯ, ПРИНЯТЫЕ В РУКОВОДСТВЕ


В этой документации отражены следующие соглашения, принятые
для ORACLE RDBMS:

Filenames (имя файла)   Имя  файла содержит заглавные буквы
       также, как и  в INIT.ORA. Часть имени файла может со-
       держать буквы нижнего регистра также,как в SGADFx.ORA.

Reserved words and keywords (зарезервированные и ключевые
слова) Эти  слова  также  состоят из заглавных букв в приме-
       рах и в текстах, этоо указывает на то, что они должны
       вводиться как есть и что они зарезервированы в ORACLE

Key names (ключевые имена)   Ключевые имена содержат заглав-
       ные буквы и заключены в квадратные скобки,как [RETURN]



СИНТАКСИС КОМАНД

Команды   Это понятие используется для идентификации  текс-
       та, который должен быть введен как
                   SELECT * FROM

Переменныe Переменные появляются на итальянском языке.  По-
       льзователи должны заменить соответствующими значени-
       ями.

Альтернативные элементы Альтернативные элементы всегда раз-
       деляются между   собой   вертикальной   чертой.Набор
       альтернативных элементов заключается в фигурные ско-
       бки, если их выборка необязательна. ( Смотрите далее
       замечания по договоренности для  обозначения  обяза-
       тельных и необязательных элементов).

Обязательные элементы Обязательные элементы  заключаются  в
       круглые скобки. Пользователь должен  выбрать один из
       элементов.

Необяхательные элементы Необязательные элементы заключаются
       в квадратные скобки.

       Отметим, что в квадратные скобки можно также заклю-
       чать части слов, как например:
                  s[elect] ...


                            -9-


Повторяющиеся элементы    Эллипс  изображает  произвольное
       число подобных элементов.

Новый или измененнный материал   Только что добавленный или
       измененный  материал отмечается  вертикальной чертой
       на "полях" страницы, как показано в этом параграфе.


Следующие символы должны быть обязательно введены в том ви-
де в каком они появляются в формате команды.

.      период
,      запятая
-      дефис
;      точка с запятой
=      знак равенства
*      звездочка
:      двоеточие
()     круглые скобки



МЫ РАДЫ ПРИНЯТЬ ВАШИ КОММЕНТАРИИ

ORACLE оценит и с уважением  примет  ваши  комментарии  как
пользователей ORACLE и как читателей этой документации. Ва-
ши замечания по записи,  корректировке и вычислениям  явля-
ются наиболее важной  получаемой  нами информацией. В конце
этого обзора находится бланк читательских комментариев, ко-
торый мы предлагаем вам  использовать, чтобы  сообщить  нам
как то, что вам понравилось так и то,  что не понравилось в
этом (  или другом) обзоре по ORACLE. Если бланк отсутству-
ет, либо вы хотите поддерживать с нами  контакты,   примите
пожалуйста следующий адрес, либо свяжитесь с нами по  теле-
фону (415) 598-8000

       Technical Publicacion Manager
       ORACLE Corporation
       20 Davis Drive
       Belmont, California  94002


                            -10-


СОДЕРЖАНИЕ

ЧАСТЬ 1:ПРЕКОМПИЛЯТОРНЫЙ ИНТЕРФЕЙС PRO*C.................17

Глава 1. Введение в Pro*C................................18
Что такое Pro*C?.........................................18
Особенности и достоинства Pro*C..........................19
Общие понятия............................................19
 Команды Pro*C...........................................20
 Смешение команд С и операторов  SQL.....................20
 Префикс команды EXEC SQL................................20
 Префикс команды EXEC ORACLE.............................21
 Выполняемые и декларативные операторы   SQL.............21
 Разделы программы на Pro*C..............................22

Глава 2. Элементы программы на Pro*C.....................23
Пролог прикладной программы..............................23
 Пролог: DECLARE SECTION.................................23
  Главные переменные.....................................24
  Правила объявления главных переменных..................25
  Индикаторные переменные................................25
  Правила объявления индикаторных переменных.............26
  Объявление указателей как главных переменных...........26
  Объявление псевдо-переменных VARCHAR...................27
  Что запрещено для DECLARE SECTION?.....................29
 Пролог: Объявление коммуникационной области SQL.........29
 ORACA, область памяти для SQLCA.........................32
 Информация в ORACA......................................32
  Новые особенности ORACA в V1.1.........................33
 Возможности ORACA.......................................34
 Пролог: связь с ORACLE..................................34
  Связь через автоматический LOGIN.......................35
  Связь через SQL*Net....................................36
Тело прикладной программы................................37
 Оператор  DECLARE   STATEMENT...........................37
 Оператор  DECLARE   DATABASE............................38
 Опции EXEC ORACLE.......................................38
 Особенности выборки в массив и связка переменных..........
 массива.................................................40
 Выборка в массив........................................40
 Ограничения на выборка в массив.........................41
 Связка переменных массива...............................41
 Общие предостережения при работе с массивами............43
 Использование фразы FOR при выборке в массив и............
 связке переменных массивов..............................43
Использование фразы FOR в операторах.......................
INSERT и UPDATE..........................................43
Образцы программ на Pro*C................................45
 Логический вход и выход в ORACLE........................45
 Создание таблицы........................................46


                            -11-


 Запрос значений при вводе строк.........................47
 Применение массивов при вводе из файла..................49
 Запрос значений при корректировке.......................52
 Корректировка с помощью массивов........................54
 Выборка с помощью массивов..............................56
 Удаление строки из существующей таблицы.................58

Глава 3. Запросы.........................................59
Части запроса............................................59
 Главные (HOST) переменные ввода.........................60
 Главные (HOST) переменные вывода........................60
Запросы, которые возвращают только одну строку...........61
Преобразование данных....................................61
 Преобразование числовых данных..........................62
 Преобразование символьных данных........................62
 Ошибки преобразований...................................63
Запросы, которые возвращают несколько строк..............63
Использование курсоров...................................63
 Оператор    DECLARE CURSOR..............................64
 Оператор    OPEN CURSOR.................................65
 Выборка строк из активной группы........................65
 Оператор    CLOSE CURSOR................................66
 Оператор    CURRENT CURSOR..............................67
 Типы курсоров...........................................67
Образцы программ.........................................68
 Запрос, содержащий фразу WHERE..........................68
 Более сложный запрос, исключающий подсказки.............71

Глава 4. Сохранение и откат результатов работы...........73
Логические единицы работы................................74
 Запуск единицы работы...................................74
 Завершение единицы работы...............................74
 Ресурсы, необходимые для выполнения единицы работы......75
COMMIT WORK (сохранение результатов работы)..............75
ROLLBACK WORK (откат результатов работы).................76
Опция RELEASE............................................76

Глава 5. Обнаружение ошибок и восстановление.............77
Использование возвращаемых значений в индикаторных.........
переменных...............................................77
 Использование индикаторных переменных и пустых..........78
 значений................................................78
  Поиск значений NULL....................................78
  Ввод значений NULL.....................................79
  Вывод значений NULL....................................79
Структура SQLCA..........................................80
 Когда обращаться к SQLCA................................81
 Обозначение отдельных элементов SQLCA...................81


                            -12-


Оператор    WHENEVER.....................................84
 Синтаксис WHENEVER......................................85
 Изменение в поведении NOT FOUND.........................85
 Сфера действия WHENEVER.................................86
 WHENEVER в сравнении с точным контролем ошибок..........86
Образцы программ.........................................87

Глава 6. Динамически определяемые операторы..............89
Понятие динамически определяемых операторов .............89
Типы динамически определяемых операторов ................90
Разрешенный ввод для динамических операторов  SQL........91
 Рекомендации по использованию операторов  DDL...........91
Метод 1: EXECUTE IMMEDIATE...............................92
 Предварительные требования для EXECUTE IMMEDIATE........92
 Ограничения на EXECUTE IMMEDIATE........................92
 Пример EXECUTE IMMEDIATE................................93
Метод 2: Использование PREPARE и EXECUTE.................94
 Ограничения для PREPARE и EXECUTE.......................94
 Пример для PREPARE и EXECUTE............................95
Метод 3: PREPARE, OPEN и FETCH...........................96
 Пример, иллюстрирующий PREPARE, DECLARE, OPEN и FETCH...97
Метод 4: Использование дескрипторов......................98
 Дескрипторная область SQL (SQLDA).......................99
  Значение отдельных элементов SQLDA....................100
 Новое в поведении DESCRIBE.............................100
 Запуск запроса на стадии исполнения....................103
  Подготовка операторов  SQL............................103
  Объявление курсора для оператора......................103
  Распределение дескриптора.............................104
  Перераспределение дескриптора.........................104
  Описание дескриптора связки...........................104
  Открытие курсора......................................104
  Описание дескриптора выборки..........................105
  Вызов строк из активной группы........................105
  Закрытие курсора......................................105

Глава 7. Вызов Pro*C (команды прекомпилятора)...........106
Что требуется для выполнения Pro*C?.....................106
Установка директории или пути...........................106
Изменения Pro*C для версии 5.1..........................106
Синтаксис команд........................................107
 Обязательные аргументы.................................107
 Опции стадии выполнения Pro*C..........................107
  AREASIZE..............................................108
  ASACC.................................................108
  BEGLABEL..............................................108
  ENDLABEL..............................................108


                            -13-

  ERRORS................................................108
  FORMAT................................................108
  Опции HOLD_CURSOR и RELEASE_CURSOR....................109
  HOST..................................................110
  INCLUDE...............................................110
  IRECLEN...............................................110
  LITDELIM..............................................110
  LNAME.................................................110
  LRECLEN...............................................110
  LTYPE.................................................111
  MAXLITERAL............................................111
  MAXOPENCURSORS........................................111
  ONAME.................................................111
  ORACA.................................................111
  ORECLEN...............................................111
  PAGELEN...............................................112
  REBIND................................................112
  SELECT_ERROR..........................................112
  USERID................................................113
  XREF..................................................113
 Пример программы, использующей REBIND..................113
Компиляция и редактирование.............................115
Условная прекомпиляция..................................115
Раздельная прекомпиляция................................116
Смешение программных интерфейсов Pro*C и ORACLE CALL....117
Что происходит во время прекомпиляции?..................117
 Контроль последовательности выполнения.................117


ЧАСТЬ 2: ИНТЕРФЕЙС Pro*C ORACLE CALL....................118


Глава 8. Введение в разработку программ с помощью
 интерфейса ORACLE CALL.................................119
Основная структура программы............................119
Область данных курсора..................................122
Область данных LOGON....................................127
Области данных программного интерфейса..................127
Общие правила кодирования...............................128
 Необязательные параметры...............................129
 Использование подстановочных переменных................130
 Использование индикаторных переменных..................131
 Рекомендации по использованию оптимизатора
 компиляции.............................................131

Глава 9. Описания отдельных программных вызовов CALL....132
Вызов OLON..............................................132
Вызов ORLON.............................................133


                            -14-


Вызов OOPEN.............................................135
Вызов OSQL3.............................................136
Вызов ODSC..............................................137
Вызов ONAME.............................................140
Вызов ODEFIN............................................141
Вызов OBNDRV и вызов OBNDRN.............................144
Вызов OOPT..............................................147
Вызов OEXEC.............................................148
Вызов OEXN..............................................149
Вызов ORES..............................................150
Вызов OFETCH............................................150
Вызов OFEN..............................................151
Вызов OBREAK............................................152
Вызов OCAN..............................................152
Вызов OCOM..............................................153
Вызов OROL..............................................154
Вызов OCON..............................................154
Вызов OCOF..............................................155
Вызов OERMSG............................................156
Вызов OCMN..............................................156
Вызов OCLOSE............................................157
Вызов OLOGOF ...........................................157

Глава 10.Типы данных....................................158
Описание типов данных...................................158
Преобразование данных...................................163

Глава 11.Старые варианты вызовов PRO*SQL (OCI)..........164
Вызов OLOGON............................................165
Вызов OSQLE.............................................166
Вызов ODSRBN............................................167
Вызов ODFINN............................................169
Вызов OBIND and OBINDN..................................170

Приложение А  Сообщения об ошибках PRO*C................173
Сообщения об ошибках PC0................................174
Сообщения об ошибках PC1................................174
Сообщения об ошибках PC2................................175
Ошибки на стадии исполнения.............................175

Приложение B  Общие рекомендации по программированию....176

Приложение C  Зарезервированные слова...................177

Приложение D  Пример программы на PRO*C.................178

Приложение E  Пример программы на PRO*C
с динамическим языком SQL...............................182


                            -15-


Приложение F  Пример программы на C.....................193

Приложение G  Справочная информация по программным
вызовам.................................................198

Алфавитный указатель........................................


                            -16-


СПИСОК ИЛЛЮСТРАЦИЙ

Рисунок 1.  Этапы написания программы на С................19
Рисунок 2.  Этапы написания программы на PRO*C............20
Рисунок 3.  Декларативные операторы   SQL.................22
Рисунок 4.  Пример DECLARE SECTION........................24
Рисунок 5.  Допустимые значения индикаторных................
............переменных....................................77
Рисунок 6.  Структура SQLCA...............................81
Рисунок 7.  Синтаксис фразы WHENEVER......................85
Рисунок 8.  Применение  WHENEVER  и  пример полного конт-...
............роля ошибок...................... ............87
Рисунок 9.  Методы программирования динамических............
            операторов  SQL.................................
Рисунок 10. Структура SQLDA.................................
Рисунок 11. Этапы выполнения (динамических) запросов........
Рисунок 12. Спецификации файлов PRO*C по умолчанию..........
Рисунок 13. Логика OCI программы для запросов SQL...........
Рисунок 14. Краткое описание программного вызова............
Рисунок 15. Расположение области данных курсора.............
Рисунок 16. Логика программы,содержащей запрос..............
            для версий V2 и V3 для  PRO*SQL(OCI)............
Рисунок 17. Внешние типы данных, поддерживаемые ORACLE......
Рисунок 18. Таблица преобразований данных...................


                            -17-



ЧAСТЬ 1. ПРЕКОМПИЛЯТОРНЫЙ ИНТЕРФЕЙС PRO*C


Следующие  разделы  содержат  описание   прекомпиляторного
интерфейса PRO*C. Часть 1 описывает цельную структуру прог-
рамм на PRO*C и представляет синтаксис  операторов   PRO*C.
Другими  рассматриваемыми темами являются обработка ошибок,
управление транзакциями, курсором, применение прекомпилято-
ра, опции команд и рекомендации  по  программированию.  Для
иллюстрации каждой представляемой концепции включены много-
численные примеры.


                            -18-



ГЛАВА 1. ВВЕДЕНИЕ В PRO*C


Эта  глава является общим введением в PRO*C. В ней обсужда-
ется применение PRO*C, общие концепции и определяения, раз-
делы  программ на PRO*C и типы  операторов,   встречающихся
в программах на PRO*C.

Язык SQL является непроцедурным языком.  То есть, большинс-
тво операторов выполняются независимо от предшествующих или
текущих операторов.  Сравните это с языками  программирова-
ния, такими как C, Fortran, Cobol или PL1. Эти языки, назы-
ваемые процедурными,  основываются на  таких  конструкциях,
как "циклы",  "ветви",  пары. Язык SQL, являясь мощным инс-
трументом в одном, тем не менее имеет ограничения из-за от-
сутствия процедурной способности.

Зная специфику созданного языка SQL как непроцедурного язы-
ка, и таким  образом  зная  ограничения,  накладываемые  на
такой язык, создатели  SQL  разработали  также  конструкции
SQL, встроенные  в процедурные языки программирования,  та-
кие как С. С помощью этих конструкций программист может ра-
зработать прикладную программу, которая будет сочетать луч-
шие свойства языка SQL и языков  программирования (главного
host языка). Эта прикладная программа является  более  мощ-
ной и  гибкой, чем программа, написанная  либо только на С,
либо только на SQL.

Система  управления   реляционными   базами  данных  ORACLE
включает несколько рабочих программ, позволяющих   програм-
мистам  писать  программы для выборки данных из базы данных
ORACLE на главном (host) языке. Известно, что рабочие прог-
раммы (tools) предусмотрены для языков С,  Fortran,  Cobol,
Pascal и PL/I.


ЧТО ТАКОЕ PRO*C?

Рабочие программы (tools) для  Pro*C, предусматриваемые   в
RDBMS ORACLE разработаны для преобразования программ на  С,
в программы, включающие операторы SQL, что даст   возмож-
ность выбирать данные в базе данных ORACLE и манипулировать
ими. В качестве прекомпилятора, PRO*C преобразовывает пред-
ложения EXEC SQL, обнаруженные во входном файле в  соответ-
ствующие вызовы (calls)  ORACLE  в  выходном   файле.  Этот
выходной файл может быть впоследствии скомпилирован, загру-
жен и выполнен обычным для программ на С способом.

Сравним Pro*C (или подобные продукты, такие как PRO*Fortran


                            -19-


и Pro*PL/I) с интерфейсом Call ORACLE (в дальнейшем называ-
емом Pro*SQL). Интерфейс Call ORACLE (OCI) является вызыва-
ющим интерфейсом для базы данных ORACLE, позволяющим  поль-
зователям базы данных внедрять вызовы (Calls) ORACLE непос-
редственно  в языки  высокого уровня, такие  как C, FORTRAN
или COBOL. Каждая транзакция выполняется  посредством  мно-
гократных вызовов и использует курсор.


ОСОБЕННОСТИ И ДОСТОИНСТВА PRO*C

Особенности компилятора Pro*C :

   *       Вызовы (Calls) Pro*C являются более концептуаль-
           ными,  и поэтому более легкими для понимания чем
           вызовы Pro*SQL (OCI).

   *       Один Pro*C (OCI) вызов автоматически  транслиру-
           ется в эквивалент отдельнговызова библиотеки ра-
           бочих программ, сокращяя  тем  самым    програм-
           мное время.

   *       Одна программа может использоваться для доступа
           к данным из различных баз данных.

   *       Множество  программ  могут быть  прекомпилирова-
           ны раздельно, а выполняться вместе.


ОБЩИЕ ПОНЯТИЯ

Использование рабочих программ для Pro*C  включает   всего
один новый шаг в обычный процесс программирования,  однако
этот  дополнительный шаг заставляет рабочую программу  для
Pro*C выполнить достаточный объем работы в  интересах  про-
граммиста. На рис. 1  показана  обычная  последовательность
действий  при  написании  и  выполнении программ написанных
на С.
Ъ--------------------------------------------------------Дї
і                                                         і
і 1. Написание программы на C.                            і
і 2. Компиляция программы, запись результата в объектный  і
і    файл.                                                і
і 3. Редактирование объектного файла, запись результата   і
і    в выполняемый файл.                                  і
і 4. Запуск программы для выполнения желаемой работы.     і
і                                                         і
А--------------------------------------------------------ДЩ

       Рис.1.  Этапы написания программы на C.


                            -20-


Если программист  внедряет операторы Pro*C в исходную прог-
рамму (PROG.C), в начало необходимо включить дополнительный
этап, как показано на рис.2.

Ъ--------------------------------------------------------Дї
і                                                         і
і 1. Написание программы на Pro*C.                        і
і 2. Прекомпиляция программы с помощью Pro*C, запись ре-  і
і    зультатов в выходной файл.                           і
і 2. Компиляция программы, запись результата в объектный  і
і    файл.                                                і
і 3. Редактирование объектного файла, запись результата   і
і    в выполняемый файл.                                  і
і 4. Запуск программы для выполнения желаемой работы.     і
і                                                         і
А--------------------------------------------------------ДЩ

       Рис.2.  Этапы написания  программы на Pro*C.


Команды Pro*C

Синтаксис и опции для запуска прекомпилятора Pro*C детально
описаны в  главе "Вызов PRO*C (команды PCC)".  В этой главе
вы можете также найти необходимую информацию  при  описании
раздельной прекомпиляции файлов для их совместного выполне-
ния и  при  описании совместного использования Pro*C и OCI.


Смешение команд С и операторов SQL

Некоторый истинный  оператор  SQL  может  быть  выполнен из
программы на С. Несмотря на то, что существуют обязательные
"разделы" или   операторы  в программах на PRO*C и основной
"порядок" их появления в программе,  отметим, что программ-
ная строка  может появляться в любой точке программы (в со-
ответствии со стандартами программирования на С,  конечно).
Эти обязательные   "разделы" представлены в главе "Элементы
программы на PRO*C" и описаны более детально в  последующих
разделах.


Префикс команд EXEC SQL

Для уменьшения языковых трудностей, которые могут появиться
из-за внедрения операторов SQL в нескольких различных глав-
ных языках,  все операторы SQL начинаются со слов EXEC SQL.
Основной целью прекомпиляции в этом случае


                            -21-


является трансляция  всех операторов,  начинающихся со слов
EXEC SQL,  в соответствующий исходному языку код  для  осу-
ществления вызова из базы данных (предположительно в коды С
в данном обзоре).


Префикс команд EXEC ORACLE

В то время,  как большинство операторов PRO*C начинается со
слов EXEC SQL,   некоторые  операторы  имеют  префикс  EXEC
ORACLE .    Хотя большинство операторов запрашивает префикс
EXEC SQL,  зафиксирован небольшой набор команд, запрашиваю-
щих префикс   EXEC ORACLE; смотрите "Опции EXEC ORACLE" для
описания и перечисления таких операторов.  Эти операторы не
совместимы с SQL и являются уникальными для прекомпиляторов
ORACLE.


Выполняемые и декларативные операторы SQL.

Операторы SQL, которые могут быть включены в программу Pro*
C, подразделяются  на две группы: выполняемые и декларатив-
ные. Все операторы, и выполняемые, и декларативные, начина-
ются со слов EXEC SQL.

Выполняемые операторы SQL являются такими операторами  SQL,
которые генерируют фактический вызов базы данных. Они вклю-
чают в себя (но не ограничиваются ими)  операторы манипули-
рования данными (DML - Data Manipulation statements),  опе-
раторы определения   данных  (  DDL   -   Data   Definition
statements) и    операторы  управления  данными (DSL - Data
Control statements).  После исполнения выполняемых операто-
ров SQLCA   (коммуникационная  область SQL),  содержит коды
возврата.

Логическая единица  работы  начинается с исполнения первого
выполняемого оператора,  исключая CONNECT.  Поэтому,   если
первый выполняемый     оператор  натолкнется  на  операторы
CONNECT, COMMIT или ROLLBACK WORK в начале новой логической
единицы работы, то это внесет определенные трудности.

Декларативные операторы SQL не генерируют код возврата и не
воздействуют на логические единицы работы. Область SQLCA не
затрагивается декларативными   операторами.   Декларативные
операторы SQL представлены на рис.3.


                            -22-


Ъ--------------------------------------------------------Дї
і                                                         і
і  #SQL Declarative Statements                            і
і--------------------------------------------------------Ді
і   BEGIN DECLARE SECTION                                 і
і   END DECLARE SECTION                                   і
і   WHENEVER...                                           і
і   DECLARE CURSOR...                                     і
і   INCLUDE...                                            і
і                                                         і
А--------------------------------------------------------ДЩ

       Рис.3. Декларативные операторы SQL.


Разделы программы на Pro*C.

Программа на Pro*C содержит два раздела, и оба они являются
обязательными для процессора Pro*C:

     *     Пролог прикладной программы (описанный в разделе
           "Пролог прикладной программы").
     *     Тело  прикладной  программы ( описан  в  разделе
           "Тело прикладной программы").

Пролог прикладной  программы  определяет  переменные и осу-
ществляет общую подготовку программы на Pro*C.  Тело  прик-
ладной программы в основном содержит вызовы Pro*C, включаю-
щие такие операторы для манипулирования данными ORACLE, как
INSERT и UPDATE. Код С может содержать несколько фрагментов
кода, запрашивающих процессор Pro*C.

Следующая глава,  "Элементы  программ на Pro*C",  описывает
пролог прикладной программы и содержит  несколько  коротких
примеров Pro*C программ  для  иллюстрации  основных принци-
пов программ на Pro*C.


                            -23-


ГЛАВА 2. ЭЛЕМЕНТЫ ПРОГРАММЫ НА PRO*C


В этой главе  определяются   обязательные элементы програм-
мы на Pro*C посредством определения некоторых терминов Pro*
C и  приводятся примеры.  В конце главы приведено несколько
коротких простых  программ, которые дадут  вам  минимальные
представления о требованиях к программам на Pro*C,  а также
кое-какие сведения   по  разработке  программ,  необходимые
для написания вашей первой программы.

В этой  главе  программа на С  обращается к модулю, который
должен быть прекомпилирован, даже если модуль содержит мно-
жество функций, либо если является только одним из несколь-
ких модулей прикладной программы.


ПРОЛОГ ПРИКЛАДНОЙ ПРОГРАММЫ

Каждая программа  на  Pro*С  начинается  с пролога приклад-
ной программы, который всегда состоит из трех частей:

1.  Раздел DECLARE SECTION, для объявления главных перемен-
    ных.

2. Оператор INCLUDE SQLCA, для определения коммуникационной
области SQL,   предусмотренной для обработки ошибок.  (Этот
оператор заменяет директиву С #include для обеспечения сов-
местимости пересекающихся языков.)

3.  Оператор CONNECT, для подключения ORACLE RDBMS.

Этим операторам  в  Pro*C  программах  могут предшествовать
только операторы, применяемые в программах на С.


Пролог:  DECLARE SECTION

В DECLARE SECTION объявляются все главные переменные, кото-
рые будут использоваться в  программе  на  С.

Раздел DECLARE SECTION начинается с оператора:

  EXEC SQL BEGIN DECLARE SECTION;

и заканчивается оператором:

  EXEC SQL END DECLARE SECTION;

Между этими  двумя операторами допустимы  только операторы,
объявляющие либо главные,либо индикаторные переменные.

                            -24-


На одну  прекомпиляционную  единицу  разрешена  только один
оператор BEGIN\END DECLARE SECTION, но программа может  со-
держать   несколько  независимых  прекомпиляционных единиц.
DECLARE SECTION может встречаться в глобальном или  локаль-
ном  декларативном разделе.

Если главная  или индикаторная переменная  встречается   в
программах на С в операторе EXEC SQL, но не  была объяв-
лена в DECLARE SECTION, то во время прекомпиляции програм-
мы появится следующее сообщение:

  Undeclared host variable a at line b in file c

где а - это имя переменной, b - номер строки, в которой она
используется, с - имя файла, использующего переменную.


Главные переменные

Главные переменные должны быть объявлены для каждого значе-
ния, упоминаемого  либо в операторах SQL, либо в операторах
программы. Тип данных этих переменных объявляется в DECLARE
SECTION с помощью операторов главного языка.  Эти типы дан-
ных не  обязательно соответствуют типам данных ORACLE,  ис-
пользуемых при определении  таблицы;  ORACLE  выполнит  все
приемлемые преобразования между типами данных главного язы-
ка и ORACLE.

Ъ--------------------------------------------------------Дї
і                                                         і
і              EXEC SQL BEGIN DECLARE SECTION;            і
і              int pempno;       /* номер служащего  */   і
і              сhar pname[11];   /* имя служащего  */     і
і              int pdeptno;      /* номер отдела  */      і
і              EXEC SQL END DECLARE SECTION;              і
і                                                         і
А--------------------------------------------------------ДЩ

Рис. 4.  Пример DECLARE SECTION

Декларация, представленная на рис. 4,  объявляет три  глав-
ных переменных (PEMPNO, PNAME, PDEPTNO), которые появятся в
далее в программе в операторах  SQL  (  в  теле  прикладной
программы):


                            -25-


       EXEC SQL SELECT DEPTNO, ENAME
           INTO :PDEPTNO, :PNAME
           FROM EMP
           WHERE EMPHO = :PEMPNO;


Правила объявления главных переменных

Главные переменные:

*  должны  быть   полностью  объявлены  в  DECLARE
   SECTION

*  должны использоваться в том же  формате  верхнего
   или нижнего регистра,что и при их объявлении

*  им должно предшествовать двоеточие в операторах SQL

*  им  не должно  предшествовать  двоеточие в операторах
   языка С

*  они не должны быть зарезервированными  для SQL словами
  (смотрите Приложение С)

*  они могут использоваться только тогда,когда можно  ис-
   пользовать константу

*  они  могут иметь связанную с ними индикаторную перемен-
   ную

(Индикаторные переменные описаны в следующем разделе).Заме-
тим, что в версии 5 Pro*C нет пустых разделяющих строк.


Индикаторные переменные

Индикаторные переменные являются необязательными перемен-
ными, которые соответствуют, одна за другой, главным  пе-
ременным, объявленным  в  разделе  DECLARE SECTION. Они в
первую очередь используются  для  работы  с  пустыми зна-
чениями (NULL).  Они  применяются для  запоминания  кодов
возврата  отдельных  полей,  определяющих, либо что "воз-
вращено пустое значение", либо что  "усечено   символьное
поле".

Индикаторные переменные могут также использоваться для вво-
да пустых значений NULL.(Смотрите "Использование возвращае-
мых значений в индикаторных переменных").


                            -26-


Правила объявления индикаторных переменных

Индикаторные переменные:

*  должны быть полностью обьявлены в  DECLARE SECTION

*  должны использовать тот же формат верхнего/нижнего   ре-
   гистра,что и при их объявлении-

*  должны быть  обьявлены   как  двухбайтные   целые   (как
   "short"  или  "short int"  в зависимости  от возможностей
   имеющегося у вас компилятора С).

*  им должно предшествовать двоеточие,если они используются
   в операторах SQL

*  если  они  используются в операторах С,  то им не должно
   предшествовать двоеточие

*  они  не  должны  быть  зарезервированными в SQL  словами
  (смотри Приложение С)

*  им должны предшествовать соответствующие главные   пере-
   менные в операторах SQL

Для примера сейчас мы добавим  две  индикаторных переменных
DEPTNOI и NAMEI в предыдущий запрос:

  EXEC SQL SELECT DEPTNO, ENAME
           INTO :PDEPTNO:DEPTNOI, :PNAME:NAMEI
           FROM EMP
           WHERE EMPNO = :PEMPNO;

Смотрите "Использование возвращаемых значений в  индикатор-
ных переменных" для более детального ознакомления с исполь-
зованием индикаторных переменных.


Обьявление указателей как главных переменных

В DECLARE SECTION вы можете использовать указатели перемен-
ных ( простые указатели), объявленные обычным  для  С  спо-
собом, используя звездочку и имя переменной, как показано в
следующем примере:


                            -27-


  EXEC SQL BEGIN DECLARE SFCTION;
  int f, j, *intptr;
  char *cp;
  EXEC SQL END DECLARE SECTION;

Когда используемое в операторе SQL имя переменной начинает-
ся с двоеточия,  звездочка не ставится, но подразумевается:

  SELECT INTFIELD INTO : intptr FROM ... ;

Для всех указателей, кроме символьных, размер изображаемого
объекта задается размером основных, указанных в декларации,
типов.  Для  символьных указателей, за  изображаемый объект
принимается строка,  заканчивающаяся значениями  типа null,
длина которой определяется  на стадии исполнения при помощи
функции определения длины строки.

Отметим, что если указатель символьной переменной использу-
ется в качестве главной переменной ввода, (во фразе USING),
его длина определяется при вызове длины строки. Это не при-
ведет к желаемым результатам, поскольку выдаст текущую дли-
ну строки, а не максимальную длину строки.


Объявление псевдо-переменной VARCHAR

В  Pro*C разрешено использование псевдо-переменных VARCHAR,
приспособленных для работы с символьными строками  перемен-
ной  длинны. Они только отображаются внутри DECLARE SECTION
и могут считаться расширением С или преддекларативной стру-
ктурой. Следующая декларация:


  EXEC SQL BEGIN DECLARE SECTION;
  VARCHAR jobDesc[40];
  EXEC SQL END DECLARE SECTION;

может быть расширена следующей структурной переменной:

  struct {
    unsigned /*2 bytes*/short int len;
    unsigned char arr[40]
    } jobDesc;

Символьный массив объявляется той же длинны, которая указа-
на в определении VARCНAR.  Поле  len идентифицирует текущую
длину строки переменной длины.


                            -28-


Переменные VARCHAR  при  определении  никогда не могут быть
объявлены как NULL. Часть  структурной  переменной  VARCHAR
len содержит значение  длины  строки  и поэтому  устанавли-
вается ORACLE тогда, когда VARCHAR используется как переме-
нная вывода. Значение len должно быть  установлено  в  про-
грамме пользователя в том случае, когда  VARCHAR  использу-
ется как переменная ввода. Пустые значения  в  массиве  arr
либо игнорируются, либо переписываются.

Символьную строку можно определить двумя способами:

       char str[100];   как символьный массив
       char *str;       или как указатель строки

Когда используется массив,  длина определяется  по  размеру
строки (т.е.  100).  Это значение принимается как для длины
входной строки, так и для длины выходной строки. ORACLE бу-
дет запоминать  буффер вывода до тех пор,  пока в программе
пользователя будет заполняться входная строка.

Переменные VARCHAR представляются в операторах SQL как сос-
тавное имя   с предшествующим двоеточием как и другие пере-
менные. Например, следующие запросы должны быть представле-
ны перед декларацией:

       EXEC SQL SELECT JOBDESC INTO :jobdesc FROM EMP
        where empno = : empno;

       или:

       getSTring(jobDesc.arr);
       /* читает описание работы, полученное от */
       /* пользоваталя                          */
       jobDesc.len = strlen(jobDesc.arr);
       /* читает длину строки                   */
       EXEC SQL SELECT ... INTO ... FROM EMP
        WHERE JOBDESC = : jobdesc;

Когда VARCHAR используется в  качестве  главной  переменной
вывода (во  фразе  INTO),  длину  поля устанавливает ORACLE
RDBMS. Когда VARCHAR используется в  качестве  главной пере-
менной ввода (во  фразе WHERE), длина поля  устанавливается
прграммно.

Для объявления указателей на тип VARCHAR  можно  воспользо-
ваться VARCHAR *ID. Можно также применять перечисленные да
лее определения стандартных для С типов, как в


                            -29-


       VARCHAR ID1[10];
       VARCHAR ID2;
       VARCHAR IDN[4];
       ...и так далее

Когда имеем дело с указателями, длина  буффера   символьной
строки определяется посредством  функции  strlen(  ).   Это
прекрасно работает для ввода и является удобным,  поскольку
в самой   программе    пользователя    нельзя    определить
len(VARCHAR)  или заполнить буффер  (массив строк).  Вывод,
однако, более запутан.  Поскольку ORACLE  определяет  длину
буффера с помощью функции strlen( ), эта длина буффера  бу-
дет необязательно видима для пользователя.   Проще объявить
и вывести буффер как  символьный  массив  (str[100]),   чем
как указатель на символьную переменную.


Что запрещено для DECLARE SECTION?

Нельзя ссылаться на объявленные в операторах имена ,  опре-
деляющие тип данных. Такие имена неизвестны для Pro*С, пос-
кольку их использование приведет к недекларированным  пере-
менным с последующими ошибками.

Нельзя обращаться к ранее поименованным структурам.  Нельзя
также объявлять переменную как некоторую структуру. Однако,
в одном из трех следующих случаев  вы  можете  использовать
структуры:

*     При  копировании  данных туда  и  назад между элемен-
      тами структуры и простыми переменными.

*     Для  доступа к полям типа Т объявите переменную  типа
      Т в DECLARE SECTION.  Затем инициализируйте указатель
      как адрес интересующего элемента структуры.

*     Для изменения  дескрипторов  и  динамических операто-
      ров, обеспечивающих  гибкость посредством локализации
      главных переменных.


Пролог: объявление коммуникационной области SQL

Каждая программа на Pro*C  обеспечивает  обработку  событий
посредством включения  в пролог прикладной программы ссылок
на коммуникационную  область  SQL.Вам  необходимо  включить
только одну строку:


                            -30-


       EXEC SQL INCLUDE SQLCA;

EXEC SQL INCLUDE используется для подключения других файлов
к вашей программе на Pro*C. Этот оператор заменяет принятое
для С подключение #include с целью обеспечения совместимос-
ти языков.    При задании EXEC SQL INCLUDE можно подключить
файлы, которые  сами содержат операторы EXEC  SQL  INCLUDE.
Число уровней вложенности лимитируется ограничениями опера-
ционной системы на количество одновременно открытых файлов.

В операторе INCLUDE необходимо использовать тот же  регистр
(верхний или   нижний),   который используется для .h файла
(обычно верхний регистр).  Pro*C должен  иметь  возможность
разместить файл  SQLCA во время прекомпиляции,  таким обра-
зом, вы имеете три выбора:

*    использовать INCLUDE = опции командной строки

*    полностью определить имя файла так, чтобы он был обна-
     ружен  Pro*C  в  общей   области   O/S,    такой   как
     SYS$ORACLE:SQLCA (для VMS).

*    скопировать файл  SQLCA, запускаемый из  РСС, в дирек-
     торию или на свой диск.

Если у вас возникли проблемы,  разрешите их,  обратившись к
DBA.

Этот оператор заставит Pro*C включить коммуникационную  об-
ласть SQL  в программу.  SQLCA может быть включена локально
или глобально.  SQLCA содержит определение переменных,  ис-
пользуемых для связи с ORACLE.  Когда программа уже преком-
пилирована, ORACLE помещает несколько деклараций переменных
главного языка на место оператора INCLUDE. Декларации обес-
печивают взаимодействие ORACLE с вашей программой при  про-
хождении информации   в процессе выполнения и устанавливает
статус выполнения различных операций. SQLCA содержит следу-
ющую информацию:

*    флаг предостережения и информацию о событиях

*    коды ошибок

*    диагностический текст

Например, вы можете контролировать успешное выполнение опе-
раторов SQL, а  также  количество  введенных  или откоррек-
тированных строк.  Либо,  если оператор выполниться с ошиб-
кой, вы можете получить подробную информацию о случившемся.


                            -31-


Таким образом, SQLCA  дает  программисту возможность выбора
различных действий в любой точке программы  основываясь  на
обратной связи с ORACLE непосредственно во время работы.

По умолчанию программа на Pro*C будет игнорировать ошибки и
продолжать процесс выпаолнения,  когда это возможно.  С по-
мощью переменных,   включенных  в SQLCA,  программист может
контролировать действия,  осуществляемые  при  определенных
обстоятельствах. Например, с помощью декларативного  опера-
тора  WHENEVER можно определить действия,  выполняемые  при
обнаружении ошибки,   предупреждении или при других опреде-
ленных обстоятельствах.  Действия могут включать  остановку
программы, уход  на другую ветвь или продолжение программы,
если это возможно.  (Оператор WHENEVER и его опции обсужда-
ются в разделе "Оператор WHENEVER").

Таким образам,   в SQLCA находится несколько переменных; мы
приведем сейчас две из них:

sqlca.sqlcode Эта  переменная содержит коды завершения каж-
       дого выполняемого оператора SQL.   Нулевое  значение
       sqlca.sqlcode означает успешное выполнение.  Отрица-
       тельное значение sqlca.sqlcode означает одну из оши-
       бок ORACLE,   представленную в сообщениях об ошибках
       ORACLE. Положительное значение sqlca.sqlcode означа-
       ет успешное   завершение  с кодом состояния ( таким,
       как конец файла).  Принят только один код состояния:
       1403, означающий, что "строка не найдена" или выбра-
       на последняя строка.

sqlca.sqlwarn Эта  переменная в действительности устанавли-
       вает восем флажков  предупреждения.  Первый  елемент
       sqlca.sqlwarn[0] устанавливает "W", если  установлен
       какой-нибудь другой флажок,что способствует быстрому
       обнаружению некоторых проблемных ситуаций.

Для более детального ознакомления с опциями обработки  оши-
бок, предоставленных  программисту, смотрите главу "Обнару-
жение ошибок  и  восстановление".   В  разделе  "  Оператор
WHENEVER " описаны опции,  предоставленные контроля ошибок.


                            -32-


ORACА, область памяти, предоставленная для SQLCA

Пользователи Pro*C  имеют  возможность запросить  получение
большего объема информации о ситуации,  возникшей во  время
прекомпиляции, что достижимо с помощью коммуникационной об-
ласти (SQLCA).  Однако,   как  только  SQLCA  задается  как
"standard SQL",  в версии 1.0 вводится коммуникационная об-
ласть ORACLE  ORACА.

ORACА может применяться только тогда,  когда включено опре-
деление ORACА заданием оператора EXEC SQL INCLUDE и выбрана
опция ORACА  = YES,  либо как опция командной строки,  либо
через SQL ORACLE OPTION.


Информация в ORACA

ORACА содержит следующую информацию:

текст текущего  оператора  SQL  (orastxt)   При обнаружении
       ошибки оказывается  особенно  полезным  восстановить
       текст тех операторов, которые анализировались ORACLE
       RDBMS (операторов, связанных с курсором). Операторы,
       которые анализируются во время прекомпиляции (такие,
       как CONNECT,  FETCH, COMMIT), не появляются в ORACА.
       В ORACА   будут отображаться самое большее первые 70
       символов оператора SQL.  Формат операторов такой же,
       что и формат сообщений об ошибках в SQLCA.

имя файла, содержащего ошибку    Если прекомпилируется нес-
       колько файлов в одной прикладной  программе,   ORACА
       определяет в каком файле обнаружена ошибка.

номер строки, содержащей ошибку   Определяет номер строки в
       файле.

ORACА включает также следующие флажки,используемые для  ус-
тановки опций  процесса  выполнения для программного интер-
фейса ORACLE:

когда сохранить оператор SQL (orastxt)  Можно выбрать усло-
       вие, при  котором оператор будет сохранен, установив
       флажок в:

       0      По умолчанию:  никогда  не  сохранять  опера-
              тор SQL.


                            -33-


       1      Сохранить  оператор  SQL  только  при обнару-
              жении ошибки SQLERROR.

       2      Сохранить оператор  SQL  либо  при  обнаруже-
              нии ошибки SQLERROR, либо при  предупреждении
              SQLWARN.

       3      Всегда сохранять оператор SQL.

предоставить операции DEBUG     Этот  флажок  должен   быть
       установлен либо в 0,  либо в 1. Если он установлен в
       1, разрешено выполнение всех операций DEBUG ( обычно
       устанавливается только флажок для буфферного курсора
       (cursor cache),описанного далее). По умолчанию уста-
       новлен 0.

контроль буфферного курсора   Если флажок установлен в 1 (и
       если флажок,  управляющий DEBUG,  также установлен в
       1), то сгенерированный при этом код будет  контроли-
       ровать состояние  буфферного  курсора  перед  каждой
       операцией над  курсором, и если обнаружится  ошибка,
       будет сгенерирован  один из кодов типа OER(21XX). По
       умолчанию устанавливается 0 для обычного контроля.


Новые особенности ORACА в версии V1.1

В версии 1.1 введено несколько новых переменных в ORACА.  В
соответствии с  другой  информацией в ORACА необходимо выб-
рать опцию ORACА = YES либо в командной строке,  либо через
EXEC  ORACLE  OPTION,  а  также   подключить   ORACА  через
INCLUDE.

Все существующие программы, использующие ORACА, должны быть
повторно прекомпилированы в версии 1.1.

orahchf (Check Heap Consistency Flag -флаг контроля  после-
довательности загрузки)  Если установлено ненулевое  значе-
       ние, генерируется контроль  последовательности  заг-
       рузки  для всей  динамической области распределения,
       предоставленной PCC. Это оказывается   удобным   для
       обнаружения  пользовательских  "жучков",  нарушающих
       область памяти. Для ORADBGF также должно быть  уста-
       новлено ненулевое значение.

Статистика буфферного (cache) курсора  Следующие флажки де-
       лают доступной  информацию,   которая  до этого была
       доступна только  в  С  через  sqlрcs  (Рrint  Cursor
       Statistics  - печать статистики курсора).


                            -34-


       orahoc   Наибольшее максимальное количество запросов
                на  открытие курсоров ORACLE.

       oramoc   Максимальное значение  числа  запрашиваемых
                ORACLE курсоров.

       oracoc   Текущее  значение   числа  открытых  ORACLE
                курсоров.

       oranor   Число переназначений буфферного курсора.

       oranpr   Число анализируемых операторов SQL.

       oranех   Число операторов SQL "выполнить".

Эти переменные устанавливаются во время  выполнения  каждой
операции COMMIT  или  ROLLBACK.  Для каждой базы данных эти
переменные устанавливаются внутренне  один раз. Поэтому те-
кущие значения в ORACА остаются теми же,  что и при послед-
ней операции COMMIT/ROLLBACK для данной базы данных.


Возможности ORACА

Применение ORACА  является необязательным,  только лишь для
повышения эффективности.Для использования ORACА необходимо:

1.   Использовать новую опцию командной строки: ORACА = YES
     (по умолчанию NO)

2.   Добавить следующую строку в программу, используя  син-
     таксис, соответствующий выбранному языку:

       EXEC SQL INCLUDE ORACА

3.   Установить необходимые флажки в  ORACА  для  выбранных
     опций.

В разделах  "Фраза  WHENEVER"  и "Структура SQLCA " описаны
восемь переменных, содержащихся в sqlca.sqlwarn.



Пролог: Связь с ORACLE

Любая программа на Pro*C должна установить связь  с  ORACLE
RDBMS перед  тем,  как получить доступ к некоторым данным в
ORACLE. Для установления  такой  связи  просто  используйте
оператор SQL CONNECT перед фразой EXEC SQL:


                            -35-


EXEC SQL CONNECT :oracleid IDENTIFIED BY :oraclepassword;

или:

EXEC SQL CONNECT :oracleid /* где oracleid = scott/tiger */

Отметим, что

*   Оператор CONNECT должен быть первым выполняемым  опера-
    тором SQL,  исполняемым в программе на Pro*C. Перед ним
    могут быть только декларативные операторы и коды С, ко-
    торые логически могут предшествовать оператору CONNECT.

*   Если пароль вводится отдельно, то должны  использовать-
    ся обе главные переменные  ORACLE username  (:oracleid)
    и password (:oraclepassword).

*   Обе главные переменные должны быть объявлены  как  сим-
    волные строки фиксированной или переменной длины. Стро-
    ки фиксированной длины должны  быть  смещены вправо  на
    бланках (на 20 символов).

*   Обе главные переменные должны инициализироваться  перед
    выполнением оператора CONNECT, иначе CONNECT завершить-
    ся ошибочно.

*   Хотя CONNECT и является первым выполняемым   оператором
    в программе, оно не может стартовать логическую единицу
    работы. Стартовать логическую единицу работы будет сле-
    дующий выполняемый оператор, встречающееся в программе.

Для инициализации двух главных переменных программист может
либо ввести значение имени пользователя  ORACLE  и  пароль,
либо включить  в  код  программы подсказку на ввод значения
имени пользователя и пароля через терминал.

Для просмотра списка декларативных операторов  SQL  обрати-
тесь к рис. 3.


Связь через автоматический Login

Если вы хотите воспользоваться таким свойством  ORACLE  как
автоматический login  (использующим  префикс OPS$ для имени
пользователя ORACLE),   необходимо  просто  передать  Pro*C
строку, содержащую слеж("/"):


                            -36-


       VARCHAR oracleid[20];
       strcpy(oracleid.arr,"/");
       oracleid.len = strlen(oracleid.arr);
       ...
       EXEC SQL CONNECT :oracleid;


Связь через SQL*Net

Pro*C поддерживает доступ к другим машинам и  базам  данных
на этих машинах через пакет SQL*Net. Например:

       EXEC SQL CONNECT :usr IDENTIFIED BY :pwd

       где:

       char userid[20] = "scott@d:750vms-t";
       char pwd[20] = "tiger";

Этот пример демонстрирует все свойственные ORACLE  действия
в пределах этой программы, выполяемые для установления свя-
зи с другой базой данных. Однако, эта возможность связи ог-
раничена только одним оператором связи CONNECT и только од-
ной базой данных.

Если вы хотите получить доступ к нескольким базам данных  в
пределах той же программы,  внесите изменения,  аналогичные
тем, что представлены в следующем примере:

       E SQL BEGIN DECLARE...
              char host1[20] = " d:750vms-t ";
              char host2[20] = " d:750vms-p ";
       E SQL END DECLARE...
              EXEC SQL DECLARE ORA1 DATABASE;
              EXEC SQL DECLARE DB2 DATABASE;
              EXEC SQL DECLARE CONNECT
              :usr IDENTIFIED BY :pwd
                   AT ORA1 USING :host1;
                   AT DB2 USING :host2;

В этом  примере  ORA1  и  DB2 являются простыми логическими
именами, используемыми в операторах связи. Фраза USING фак-
тически определяет рабочую сеть,  машину и базу данных, ко-
торые связаны с именами ORA1 или DB2.  Имена  ORA1  и  DB2,
также, как и имена курсора или имена операторов, не являют-
ся главными переменными, но определяют имя для данного слу-
чая использования.


                            -37-


ТЕЛО ПРИКЛАДНОЙ ПРОГРАММЫ

Тело прикладной программы содержит операторы SQL для запро-
са и манипуляции данными, хранящимися в базе данных ORACLE.
Эти операторы называются операторами манипулирования данны-
ми ( или DML для Data Manipulation Language). Тело приклад-
ной программы может также содержать  операторы  определения
данных (   или  DDL для Data Definition Language),  которые
применяются для создания или определения  структур  данных,
таких как таблицы, индексы или экранные формы.

В этом документе мы в первую очередь обсудим операторы SQL,
которые осуществляют операции INSERT,  UPDATE, DELETE пото-
му, что  они  являются  концептуально более простыми.  (Эти
строки просто возвращают код, определяющий успешное или не-
успешное выполнение операции, что более предпочтительно,чем
возврат строк данных.  Количество обрабатываемых строк ука-
зано в SQLCA.)

Затем мы продвинемся к запросам (операторам SELECT),  кото-
рые далее будут подразделяться на:

*   запросы, возвращающие только одну строку, или

*   запросы, возвращающие более, чем одну строку.

Далее будет определен запрос, позволяющий использовать кур-
сор, который описывается в разделе "Применение курсоров ".

В заключение,   мы обсудим типы операторов SQL,  называемых
динамически определяемыми операторами.  Динамически опреде-
ляемые операторы   SQL могут изменяться от выполнения к вы-
полнению и являются очень гибким инструментом, позволяющим,
создавать разнообразные  и очень гибкие прикладные програм-
мы, хотя  и являются более сложными для понимания.  В главе
"Динамически определяемые  операторы" иллюстрируется приме-
нение динамически определяемых операторов SQL в прoграммах.
Отметим, что  динамически определяемые операторы могут быть
разделены на два класса:  с известной структурой оператора,
когда используется немедленное выполнение,  и с заранее не-
известной структурой оператора,  когда используется  подго-
товка. Как    немедленное выполнение,  так и преварительная
подготовка, описаны в главе 6.


Оператор DECLARE STATEMENT

Имеется еще один новый оператор, подобный DECLARE CURSOR:


                            -38-


       EXEC SQL DECLARE s STATEMENT;

который может применяться для спецификации управляющих опе-
раторов. Для примера приведем фрагмент  программы  на С, не
имеющей места в более ранних версиях прекомпилятора:

       main()
       {
       init();
       execute();
       }
       execute();
       {
       EXEC SQL EXECUTE S;
       }
       init();
       {
       EXEC SQL PREPARE S FROM
              "INSERT INTO EMP (ENAME) VALUES ('WILMA');
       }

потому, что  когда  встретится EXECUTE S,  значение S будет
неопределено (т.к.   S определяется в PREPARE).  В версии 1
Pro*C можно ввести следующий оператор в раздел main() прог-
раммы и программа будет работать:

       EXEC SQL DECLARE S STATEMENT;



Оператор DECLARE DATABASE

Оператор

       EXEC SQL DECLARE ORA1 DATABASE

используется для  установления связи и взаимодейстия с дру-
гой базой данных через сеть SQL*Net.


Опции EXEC ORACLE

Оператор EXEC  ORACLE  OPTION позволяет задавать  в  строке
программы опции, которые ранее могли быть определены только
во время выполнения. Опции теперь могут определяться как во
время выполнения,  так и в строке программы,  что дает воз-
можность динамически   изменять  ситуацию внутри программы.
Для просмотра списка опций,  которые могут  определяться  с
помощью оператора EXEC ORACLE OPTION, задайте PCC.
Опции, помеченные звездочкой,  могут  задаваться  в  строке
программы.


                            -39-


       EXEC ORACLE OPTION ( option=option_arg );

Опции:

*   AREASIZE

*   ERRORS

*   INCLUDE

*   LITDELIM

*   MAXLITERAL

*   MAXOPENCUSOR

*   REBINDS

*   SELECT_ERROR

*   XREF

Например, можно изменить AREASIZE на базе изменения от кур-
сора к курсору:

       EXEC ORACLE OPTION ( AREASIZE=4 );
       EXEC SQL SELECT ENAME
            INTO :ename
            FROM EMP;
       EXEC SQL DECLARE C1 CURSOR FOR SELECT ENAME FROM EMP;
       EXEC ORACLE OPTION ( AREASIZE=8 );
       EXEC SQL OPEN C1;

В этом примере первый оператор открывает курсор с  размером
памяти в 4К,  а второй оператор открывает курсор с размером
памяти в 8К. Даже если распределение области памяти курсора
является динамическим, эта опция позволяет изменить базовое
распределение памяти для различных операторов SQL.

Оператор EXEC ORACLE OPTION также облегчает трудности, име-
ющиеся для операционных систем в связи с ограничением числа
символов, которые могут появляться в командной строке.

Опции, введенные в строке программы,  перекроются такими же
опциями, введенными в командной строке.  Можно также помес-
тить опции EXEC ORACLE в отдельный файл и включить их пред-
ложением EXEC SQL INCLUDE в подходящем месте программы.


                            -40-


Особенности выборки в массив и связки переменных массива

Начиная работать с версией 1.1 Pro*C  вы  можете  выполнить
операторы DML,   используя массивы главных переменных.  Это
означает, что более предпочтительным,  чем в версии  4  РРС
ORACLE, станет  предложенное в Pro*C объявление главных пе-
ременных как массивов для дальнейшего применения их в  опе-
раторах INSERT, UPDATE, SELECT.


Выборка в массив

Далее представлены несколько фрагментов программ,  ярко де-
монстрирующих применение трех массивов (ENAME,  EMPNO, SAL)
для выборки до 100 имен. Представлены два различных примера
выборки, в  которых  используется  один  и  тот  же  раздел
DECLARE SECTION.

EXEC SQL BEGIN DECLARE SECTION;
       char ename [100] [10];
       int empno [100];
       float sal [100];
EXEC SQL END DECLARE SECTION;

       Пример А

EXEC SQL SELECT ename, empno
       INTO :ename, :empno
       FROM EMP;

       Пример В

EXEC SQL DECLARE C1 CURSOR FOR
       SELECT ename, empno
       FROM EMP;
EXEC SQL OPEN C1;
EXEC SQL WHENEVER NOT FOUND GOTO...
EXEC SQL FETCH C1 INTO :ename, :empno;

Пример А демонстрирует выборку нескольких строк  непосредс-
твенно в два массива главных переменных. Приняти менее, чем
100 строк,  либо просмотр 100 строк,  можно осуществить без


                            -41-

применения курсоров.   Если  вы  хотите  выбрать  более 100
строк, обратитесь к примеру В и выполните выборку множество
раз вплоть  до  конца  выборки.   Если выбирается более 100
строк и вы выполняете выборку SELECT повторно таким  спосо-
бом, что предложен в примере А, вы восстановите только пер-
вые 100 строк. Для просмотра более 100 строк необходимо ис-
пользовать выборку  множества  строк ( с помощью курсора ),
но в действительности вы будете  выбирать  "пакет"  из  100
строк.


Ограничения на выборку в массив

На выборку строк с помощью массивов накладывается одно  ог-
раничение. Оператор   SELECT во фразе WHERE не может содер-
жать массив.  Это создаст двусмысленную ситуацию и приведет
поэтому к   ошибке.   Если вы будете использовать массив во
фразе WHERE, получите сообщение об ошибке:

       array not legal in WHERE clause

В следующей таблице показано, какое применение допустимо, а
какое нет.

SELECT......INTO......WHERE......VALID
--------------------------------------
            array     array       no
            scalar    scalar      yes
            array     scalar      yes
            scalar    array       no


где  array  - массив, а
     scalar - скаляр

Отметим, что массивы можно применять и во фразе WHERE,   но
в операторах UPDATE (смотрите следующий раздел).



Связка переменных массива

Предыдущие примеры  демонстрировали выборку в массив; можно
также сделать связку переменных массива при их  использова-
нии в операторах DML (INSERT и UPDATE). В следующем примере
предполагается наличие того же раздела DECLARE SECTION, что
и в примерах А и В:


                            -42-


    EXEC SQL INSERT INTO EMP (ENAME, EMPNO, SAL)
         VALUES (:ename,:empno,:sal);

(Предполагается также,  что массивы (ename, empno, sal) за-
полнены до их использования в операторах INSERT.)

Операторы UPDATE допускают также, но с некоторыми ограниче-
ниями, использование массивов главных переменных. Можно од-
новременно использовать массивы и во фразе SET,  и во фразе
WHERE. В операторах UPDATE нельзя смешивать массивы главных
переменных и простые переменные (скаляры). Например:

    EXEC SQL UPDATE EMP SET SAL = :sal WHERE EMPNO = :empno;

В этом  случае  обе  главные  переменные могут одновременно
быть либо скаляром,  либо массивом, а  их типы должны соот-
ветствовать. Если  sal  определяется как массив из 100 эле-
ментов, то empno тоже должен быть определен как массив того
же размера.   (  Хотя типы переменных и должны соответство-
вать, соответствие типов данных необязательно, например, вы
можете присвоить  записи выбранных 100 чисел 100 новых зна-
чений данных).

В следующей таблице показано, какое применение допустимо, а
какое нет.

UPDATE......SET.......WHERE......VALID
--------------------------------------
            array     array       yes
            scalar    scalar      yes
            array     scalar      no
            scalar    array       no

В том случае,  когда обе главные переменные являются масси-
вами, оператор эквивалентен следующему:

    for (i=0;i<= max_array_index;i++)
       update emp set sal = sal[i] where empno = empno[i];

Здесь продвижение происходит таким образом, как если бы оба
массива при  столкновении поднимались выше к следующим эле-
ментам в каждом массиве.


Общие предостережения при работе с массивами

Если вы используете более одного массива главных переменных
в операторе  SQL,  и  массивы  имеют  разную   размерность,
Pro*C генерирует предупреждение:


                            -43-


       ARRAY SIZE MISMATCH

во время прекомпиляции.  Однако, это только предупреждающее
сообщение. Pro*C  будет использовать наименьший из массивов
для определения числа элементов, используемых в операторе.

Версия 1  Pro*C  будет  обнаруживать ошибочные фразы UPDATE
для нединамических операторов SQL.  Однако,  это  позволяет
программисту контролировать и значения,  используемые в ди-
намических операторах SQL.


Использование фразы FOR при выборке в массив
и связке переменных

Ключевое слово FOR можно  применять  в  Pro*C для установки
числа используемых элементов массивов  главных  переменных.
Это оказывается полезным, если вы хотите  выполнить  опера-
тор SQL только для части массива. Например:

EXEC SQL BEGIN DECLARE SECTION;
       int empno [100];
       int loop;
EXEC SQL END DECLARE SECTION;

loop=50;         /*установите цикл для части массива*/

EXEC SQL FOR :loop SELECT EMPNO INTO :empno FROM EMP;

Во фразе  FOR будет указывается действительное число запра-
шиваeмых элементов в массиве, поэтому будьте осторожны,что-
бы не задать число, большее, чем действительный размер мас-
сива.

ПРЕДУПРЕЖДЕНИЕ: Это  может вынудить программу писать поверх
других областей данных внутри программы и привести к ненор-
мальному завершению.


Применение фразы FOR в операторах UPDATE и INSERT

Фраза FOR оказывается особенно полезной  при  использовании
ее в   операторах UPDATE и INSERT.  Эта фраза позволяет ис-
пользовать не весь массив (по умолчанию).  При  помощи  FOR
можно ограничить   количество  используемых в данный момент
элементов нужным вам числом.


                            -44-


Ъ--------------------------------------------------------Дї
і      EXEC SQL WHENEVER NOT FOUND CONTINUE;              і
і                                                         і
і      rows_to_fetch = 10;                                і
і      /* число строк,выбранных в каждый блок        */   і
і      rows_last_time = 0;                                і
і      /* число строк,выбранных в последний раз      */   і
і      rows_this_time = 0;                                і
і      /* число строк,выбранных в этот раз           */   і
і                                                         і
і      do                                                 і
і      {                                                  і
і        EXEC SQL FOR :rows_to_fetch FETCH...;            і
і                                                         і
і      rows_this_time = sqlca.sqlerrd[2] - rows_last_time;і
і      rows_last_time = sqlca.sqlerrd[2];                 і
і                                                         і
і      if ( rows_this_time != 0)                          і
і         {                                               і
і          /* Сделайте выборку,т.к. необходимо ввес- */   і
і          /* ти эти строки.                         */   і
і           EXEC SQL FOR :rows_this_time INSERT...;       і
і          }                                              і
і                                                         і
і      } while ( rows_this_time == rows_to_fetch )        і
і                                                         і
А--------------------------------------------------------ДЩ


                            -45-


ОБРАЗЦЫ ПРОГРАММ НА PRO*C


Отметим,что измененные  и  дополненные  варианты  примеров,
представленных в этом обзоре, предусмотрены на дистрибутив-
ной ленте.  Вы можете обнаружить,  что примеры на дистрибу-
тивной ленте очень незначительно отличаются от представлен-
ных в документации.



Логический вход и выход из ORACLE

Первый пример представляет наиболее общий вариант программы
на PRO*C: просто вход и выход из ORACLE.

/* Пример #1 */
#include 

/*========================================================*/
/*    Это пример программы на PRO*C,которая осущесвляет   */
/*    вход в базу данных ORACLE для scott/tiger.          */
/*========================================================*/

EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
       /* логический вход в ORACLE       */
       strcpy(uid.arr,"SCOTT");
       /* копирование имени пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGER");
       /* копирование пароля             */

       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connectid to ORACLE user:%s\n",uid.arr);
       EXEC SQL COMMIT WORK RELEAS;
       /* логический выход из базы данных */
       exit(0);
}


                            -46-


Создание таблицы

В этом примере мы создадим таблицу с именем EMP_TEST,содер-
жащую колонки EMPNO,ENAME,JOB,MGR,HIREDATE,SAL и DEPTNO.

/* Пример #2 */
#include 

/*========================================================*/
/*    Это пример программы на PRO*C,которая создает       */
/*                таблицу.                                */
/*========================================================*/

EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
       /* логический вход в ORACLE       */
       strcpy(uid.arr,"SCOTT");
       /* копирование имени пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGER");
       /* копирование пароля             */

       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connectid to ORACLE user:%s\n",uid.arr);

       EXEC SQL CREATE TABLE EMP_TEST
         (empno number,ename char(15),job char(10),
          mgr number,hiredate date,sal number,
          deptno number);

       printf("Table emp_test created \n");

       EXEC SQL COMMIT WORK RELEAS;
       /* логический выход из базы данных */
       exit(0);
}


                            -47-


Запрос значений при вводе строк

Этот пример демонстрирует включение строк в таблицу при по-
мощи подсказки пользователю о вводе записи, которую необхо-
димо ввести в таблицу.

/* Пример #3 */
#include 

/*========================================================*/
/*    Это пример программы на PRO*C,которая вводит записи */
/* в таблицу EMP,используя подсказку пользователю о вводе */
/* значений.                                              */
/*========================================================*/

EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
       int empno;
       VARCHAR ename[15];
       VARCHAR job[10];
       float sal;
       int deptno;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
       /* логический вход в ORACLE       */
       strcpy(uid.arr,"SCOTT");
       /* копирование имени пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGER");
       /* копирование пароля             */

       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connectid to ORACLE user:%s\n",uid.arr);

       while (1)
       {
       printf("Enter employee number (or 0 to end):  ");
       sret = scanf("%d",&empno);
       if (sret == EOF !! sret == 0 !! empno == 0)
             break;
       /* прервать цикл                  */
       printf("Enter employee name:  ");


                            -48-


       scanf("%s",ename.arr);
       ename.len=strlen(ename.arr);
       /* установить длину ename          */
       printf("Enter employee's job:  ");
       scanf("%s",job.arr);
       job.len=strlen(job.arr);
       /* установить длину job            */
       printf("Enter employee salary: ");
       scanf("%f",&sal);
       printf("Enter employee deptno: ");
       scanf("%d",&deptno);

       EXEC SQL INSERT INTO EMP
       (empno,ename,job,deptno)
       VALUES(:empno,:ename,:job,:deptno);
       EXEC SQL COMMIT WORK ;

       printf("Employee %s added.\n\n",ename.arr);
       }

       EXEC SQL COMMIT WORK RELEAS;
       /* логический выход из базы данных */
       exit(0);
}


                            -49-


Применение массивов при вводе из файла

В этом  примере читаются данные из файла и вводятся,  с по-
мощью массивов в существующую таблицу.


/* Пример #4 */
#include 

/*========================================================*/
/*    Это пример программы на PRO*C,использующей фразу FOR*/
/* для внесения записей в таблицу EMP.Это осуществляется  */
/* посредством чтения данных из файла,записи их в массивы */
/* и последующего ввода из этих массивов.Данные в файле   */
/* будут в символьном формате и разделяться пробелами.Это */
/* позволит использовать функцию fscanf.                  */
/*========================================================*/

EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
       int empno;
       VARCHAR ename[15];
       VARCHAR job[100][10];
       VARCHAR hiredate[100][9];
       float sal[100];
       int deptno[100];
       int loop;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

FILE *fp;
/* указатель файла                */

main()
{
       /* логический вход в ORACLE       */
       strcpy(uid.arr,"SCOTT");
       /* копирование имени пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGER");
       /* копирование пароля             */

       EXEC SQL WHENEVER SQLERROR GOTO errept;
       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connectid to ORACLE user:%s\n",uid.arr);


                            -50-


       if ((fp= fopen("test.dat","r")) == NULL)
       {
       printf("Error opening file test.dat. \n");
       }

       while (1)
       /* выполните это множество раз       */
       {
            for(i=0;i < 100;i++)
            /* от 0 до 99                    */
            {
               fsret=fscanf(fp,"%d %s %s %s %f %d",
                &empno-i-,ename[1].arr,job[i].arr,
                &hiredate[i].arr,&sal[i],&deptno[i]);
               if (fsret == EOF)
                    break;
               /* прочитано менее 100 значений */
               if (fsret == 0)
               /* обнаружена ошибка в строке   */
               {
                 printf("Incompatible field on the line.\n");
                 exit(1);
                }
               ename[i].len=strlen(ename[i].arr);
               job[i].len=strlen(job[i].arr);
               hiredate[i].len=strlen(hiredate[i].arr);
             }
             loop = i;
             /* установить итерации цикла    */
             EXEC SQL FOR :loop
             INSERT INTO EMP
             (empno,ename,job,hiredate,sal,deptno)
             VALUES(:empno,:ename,:job,:hiredate,:sal,:deptno);

             EXEC SQL COMMIT WORK ;

             printf("%d rows inserted.\n",sqlca.sqlerrd[2]);

             if (loop < 100)
             /* последняя итерация  цикла    */
                 break;
             /* выход из цикла               */
       }

       printf("File test.dat loaded. \n");
       EXEC SQL WHENEVER SQLERROR CONTINUE;
       EXEC SQL COMMIT WORK RELEAS;


                            -51-


       /* логический выход из базы данных */
       exit(0);
errrpt:
       printf("\n %.70s \n",sqlca.sqlerrm.sqlerrmc);
       EXEC SQL ROLLBACK WORK RELEAS;
       /* логический выход из базы данных */
       exit(1);

 }


                            -52-


Запрос значений при корректировке

В этом  примере для корректировки вначале выходит подсказка
для ввода имени служащего, для которого должна быть измене-
на запись, а затем запрашивается ввод изменяемых значений.

/* Пример #5 */
#include 

/*========================================================*/
/*  Это пример программы на PRO*C,использующей подсказку  */
/* пользователю о необходимости ввода имени служащего и   */
/* высвечивающей текущую зарплату и назначение для этого  */
/* служащего.Затем будет выведена подсказка пользователю  */
/* для ввода новой зарплаты и назначения и будет сделана  */
/* корректировка таблицы EMP для этого служакщего.        */
/*========================================================*/

EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
       VARCHAR ename[10];
       float sal,comm;
       short sal,comm;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
       int sret;
       /* логический вход в ORACLE       */
       strcpy(uid.arr,"SCOTT");
       /* копирование имени пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGER");
       /* копирование пароля             */

       EXEC SQL WHENEVER SQLERROR STOP;
       EXEC SQL WHENEVER NOT FOUND STOP;
       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connectid to ORACLE user:%s\n",uid.arr);

       printf("Enter employee name to update:  ");
       scanf("%s",ename.arr);
       ename.len=strlen(ename.arr);
       EXEC SQL SELECT SAL,COMM INTO :sal,:comm


                            -53-


       FROM EMP
       WHERE ENAME=:ename;
       printf("Employee: %s  sal: %6.2f  comm: %6.2f \n",
               ename.arr,sal,comm);

       printf("Enter new salary:  ");
       stret=scanf("%f",&sal);
       sali = 0;
       /* установить индикатор           */
       if (sret == EOF !! sret == 0 )
       sali = -1;
       /* установить индикатор для NULL  */
       printf("Enter new commision:  ");
       stret=scanf("%f",&comm);
       commi = 0;
       /* установить индикатор           */
       if (sret == EOF !! sret == 0 )
       commi = -1;

       EXEC SQL UPDATE EMP
       SET SAL=:sal:sali,COMM=:comm:commi
       WHERE ENAME=:ename;

       printf("Employee %s updated.\n",ename.arr);

       EXEC SQL COMMIT WORK RELEAS;
       /* логический выход из базы данных */
       exit(0);
}


                            -54-


Корректировка с помощью массивов

В этом  примере выдается подсказка на ввод номеров служащих
и новых окладов и затем осуществляется корректировка данных
с помощью массивов.


/* Пример #6 */
#include 

/*========================================================*/
/*    Это пример программы на PRO*C,использующей массивы  */
/* главных переменных для корректировки таблицы. Массивы  */
/* будут загружаться значениями из входного потока от опе-*/
/* ратора.Отметим следующую закономерность для указания   */
/* массивов в операторах UPDATE: как во фразе SET, так и  */
/* во фразе WHERE должны быть заданы главные переменные   */
/* ного и того же типа:либо массив,либо скаляр.           */
/*========================================================*/

EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
       int empno[100];
       float sal[100];
       int loop;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;


main()
{
       int i;
       /* счетчик массива                */
       int stret;
       /* код возврата scanf             */

       /* логический вход в ORACLE       */
       strcpy(uid.arr,"SCOTT");
       /* копирование имени пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGER");
       /* копирование пароля             */

       EXEC SQL WHENEVER SQLERROR GOTO errept;
       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connectid to ORACLE user:%s\n",uid.arr);


                            -55-


       while (1)
       /* выполните это множество раз       */
       {
            for(i=0;i < 100;i++)
            /* от 0 до 99                    */
            {
             printf("Enter employee number  (or  0  to  end
                     loop): ");
             stret=scanf("%d",&empno[i]);
             if (sret == EOF !! sret == 0 !! empno[i] == 0)
                break;
             printf("Enter updated salary:  ");
             stret=scanf("%f",&sal[i]);
             if (sret == EOF !! sret == 0 )
             {
                printf("Error in entry; termination at this
                        empno.\");
                break;
             }
       }

       if (i == 0)      /* конец   ?????? completely */
                break;

       loop = i;       /* установить число иттераций */

       EXEC SQL FOR :loop
            UPDATE EMP SET SAL = :sal WHERE EMPNO = :empno;

       EXEC SQL COMMIT WORK;

       printf("%d rows updated.\n",sqlca.sqlerrd[2]);

       }

       printf("Update programm complete. \n");

       EXEC SQL WHENEVER SQLERROR CONTINUE;
       /* следующая ошибка не ловится                 */

       EXEC SQL COMMIT WORK RELEAS;
       /* логический выход из базы данных */
       exit(0);

errrpt:
       printf("\n %.70s \n",sqlca.sqlerrm.sqlerrmc);
       EXEC SQL ROLLBACK WORK RELEAS;
       /* логический выход из базы данных */
       exit(1);
}


                            -56-



Выборка с помощью массивов

Этот пример программы демонстрирует  запрос,   возвращающий
три колонки из таблицы через массивы главных переменных.

/* Пример #7 */
#include 

/*========================================================*/
/* Это пример программы на PRO*C,  в которой осуществля-  */
/* выборка, используя массивы главных переменныех. Отме-  */
/* тим следующую закономерность для массивов в операторах */
/* SELECT. Фраза WHERE может содержать не массивы глав-   */
/* ных переменных, а скалярные главные переменные (пере-  */
/* менные с одним значением).                             */
/*========================================================*/

EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
       VARCHAR ename[100][15];
       int empno[100];
       float sal[100];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
       long num_ret;
       /* число возвращаемых строк       */

       /* логический вход в ORACLE       */
       strcpy(uid.arr,"SCOTT");
       /* копирование имени пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGER");
       /* копирование пароля             */

       EXEC SQL WHENEVER SQLERROR GOTO errept;
       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connectid to ORACLE user:%s\n",uid.arr);

       EXEC SQL DECLARE C1 CURSOR FOR
                SELECT EMPNO,ENAME,SAL FROM EMP;
       EXEC SQL OPEN C1;
       EXEC SQL WHENEVER NOT FOUND GOTO endloop;
       num_ret = 0;    /*инициализация числа строк  */


                            -57-



       while(1)        /*выполнить это несколько раз*/
       {
          EXEC SQL FETCH C1 INTO :empno,:ename,:sal;
          print_rows(sqlca.sqlerrd[2] - num_ret);
          num_ret = sqlca.sqlerrd[2];
       }
endloop:
       if (sqlca.sqlerrd[2] - num_ret > 0);
           print_rows(sqlca.sqlerrd[2] - num_ret);
           /*вызвать последний раз           */

       printf("\n\nProgram complete. \n");

       EXEC SQL WHENEVER SQLERROR CONTINUE;
       /* следующая ошибка не ловится                 */

       EXEC SQL COMMIT WORK RELEAS;
       /* логический выход из базы данных */
       exit(0);

errrpt:
       printf("\n %.70s \n",sqlca.sqlerrm.sqlerrmc);
       EXEC SQL ROLLBACK WORK RELEAS;
       /* логический выход из базы данных */
       exit(1);
}

print_rows(n)

long n;
{
       long i;      /* используйте счетчик строк */

       printf("\n\nEmployee number\tEmployee Name\tSalary\n");
       printf("\n\n---------------\t-------------\t------\n");

       for(i=0;i

/*========================================================*/
/* Это пример программы на PRO*C,  в которой осуществля-  */
/* удаление строк из таблицы emp после выдачи подсказки   */
/* на ввод номера служащего.                              */
/*========================================================*/

EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
       int empno;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
       /* логический вход в ORACLE       */
       strcpy(uid.arr,"SCOTT");
       /* копирование имени пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGER");
       /* копирование пароля             */

       EXEC SQL WHENEVER SQLERROR GOTO errept;
       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connectid to ORACLE user:%s\n",uid.arr);

       printf("Enter employee number  to delete: ");
       scanf("%d",&empno);

       EXEC SQL DELETE FROM EMP WHERE EMPNO = :empno;

       EXEC SQL COMMIT WORK RELEAS;
       /* логический выход из базы данных */

       printf("Employee number %d dropped.\n",empno);
       exit(0);
}

                            -59-



ГЛАВА 3.ЗАПРОСЫ

В этой главе  рассматривается понятие курсоров, применяемых
для возвращения  результатов  большинства  запросов.  После
рассмотрения различных команд курсора приведено два примера
программ.

Запросы могут быть интересными и полезными типами  операто-
ров DML. Однако, поскольку до этого мы интересовались толь-
ко успешным или неуспешным завершением транзакций,  а не их
результатами (таблицами   с  различным числом строк и коло-
нок), запросы  потребуют  дополнительного  кодирования.   В
простейшем случае,  когда запрос возврашает одну строку, он
может быть кодирован также, как обычная программа в послед-
ней главе.  Наиболее часто, однако, запросы возвращают нес-
колько строк, либо число строк в результате не может быть с
гарантией равно единице.  Если возвращается более, чем одна
строка, то  необходимо использовать понятие курсора, а при-
менение курсора  потребует включения дополнительных вызовов
Pro*C. (Если запрос пишется для возврата только одной стро-
ки, а  в действительности может возвращать несколько, возв-
ращается только первая строка).

В этой главе мы вначале рассмотрим запросы, которые заведо-
мо возвращают одну строку, затем рассмотрим понятие  курсо-
ров и их  применение в  запросах, возвращающих  более, чем
одну строку.


Части запроса

Запросы, написанные на Pro*C,  могут содержать оператор SQL
SELECT, включающее следующие фразы:

  SELECT
  INTO
  FROM
  WHERE
  CONNECT
  UNION
  INTERSECT
  MINUS
  GROUP BY
  HAVING
  ORDER BY

(Эти ключевые слова все применялисьь в  SQL*Plus, за исклю-
чением   INTO,  которое  использовалось  в   прекомпиляторе
SQL*Forms и Pro*SQL). Рассмотрим пример:


                            -60-


  EXEC SQL SELECT ENAME, SAL + 1000, JOB
           INTO :ENAME, :SAL, :JOB
           FROM EMP
           WHERE EMPNO = :EMPNO;

Поля (ENAME, JOB) или выражения (SAL + 1000), следующие  за
ключевым словом SELECT являются ячейками, которые  содержат
список выборки. Таким образом, наш  список  SELECT содержит
три ячейки. Основываясь на  критерии  выборки, определяемом
фразой WHERE (и следующими за ней фразами, если они присут-
ствуют), ORACLE будет возвращать одну строку в  переменные,
специфицированные во фразе INTO (:ENAME, :SAL, :JOB).

Количество переменных в списке SELECT должно быть равно ко-
личеству  переменных,  определенных во фразе INTO, т.к. они
являются тем местом,  куда помещается  каждое  возвращаемое
значение.  Если  два списка содержат  неравное число ячеек,
будет   возвращено   наименьшее   число    значений   и   в
sqlca.sqlwarn[3]  будет помещено "W". ( Смотрите   описание
sqlca.sqlwarn[3]  в разделе "Значение  отдельных  элементов
SQLCA").


Главные переменные ввода

Главные  переменные  во  фразе  WHERE  называются  главными
переменными ввода, потому что они обеспечивают информацией,
необходимой перед осуществлением запроса. Для связи с пере-
менными берутся их адреса, узнаваемые в  ORACLE RDBMS.  На-
пример, значение главной переменной ввода  PEMPNO может пе-
редаваться через параметр в программе на Pro*C или запраши-
ваться через подсказку во время выполнения. Эти переменные
также называются  переменными связки или пользовательскими
переменными.  Они  могут  применяться тогда,  когда  могут
применяться константы.


Главные переменные вывода

Главные  переменные во фразе INTO называются главными пере-
менными вывода, потому, что они влияют на результаты  пред-
ложения SELECT после выполнения. Эти переменные также назы-
ваются переменными определения или into-переменными.

(Если  запрос  возвращает более чем одну строку, фраза INTO
не применяется в  операторе  SELECT, взамен  вы  объявляете


                            -61-


курсор,  который используется для передачи результатов зап-
роса. Смотрите раздел "Запросы которые возвращают несколько
строк").



ЗАПРОСЫ, КОТОРЫЕ ВОЗВРАЩАЮТ ТОЛЬКО ОДНУ СТРОКУ

Если вы знаете, что ваш запрос будет возвращать только одну
строку, вы  можете  использовать фразу INTO,  с таким коли-
чеством  главных  переменных вывода, сколько ячеек в списке
SELECT. Например, если вы запрашиваете записи,  основываясь
на значениях уникального индекса, вы  должны  предусмотреть
возврат более одного (либо ни одного) значения, как в:

    SELECT ENAME, SAL, JOB, MGRNO
    INTO :ONAME, :OSAL, :OJOB, :OMGR
    FROM EMP
    WHERE SSNO = 130443139;

где "SSNO" есть числовая колонка значений социальной гаран-
тии, имеющая уникальное значение.

Если условиям запроса удовлетворяет более, чем одна строка,
и  SELECT_ERROR установленна в NO,  то возвращается  только
первая  строка. Если SELECT_ERROR  установленна в YES  ( по
умолчанию),  Pro*C  выдаст ошибку  (OER2112), в том случае,
если возвращена более чем одна строка. Смотрите главы 2 и 7
для  получения дополнительной информации.



ПРЕОБРАЗОВАНИЕ ДАННЫХ

Перед  передачей каждого значения из списка SELECT, связан-
ного с главными переменными, ORACLE  RDBMS  преобразовывает
значения  данных, если это необходимо, в тип данных главных
переменных. Преобразование  данных  может быть  также в том
случае, когда ORACLE  RDBMS  передает значения из столбца в
столбец или из главной переменной ввода в столбец.

Несмотря на тип данных,  если  возвращается  значение  NULL
главной  переменной вывода, индикатор переменной устанавли-
вается в -1. Если нет  индикаторной  переменной,то  SQLCODE
устанавливается в -1405.

Следующие  параграфы описывают, как работает преобразование
и что необходимо для этого.


                            -62-


Преобразование числовых данных

Когда преобразуются числовые данные, следующие ситуации  не
будут выдавать ошибку или предупреждение:

    *      смещение нулей влево

    *      усечение дробной части (точки) десятичного числа
           или числа с плавающей точкой

Любая другая потеря информации рассматривается как "ошибка"
и описывается в следующем разделе.

Преобразование  в  целые значения:  Преобразование числовых
данных к данным целого типа  осуществляется  усечением дан-
ных. Усечение происходит в направлении нулей; усечение про-
исходит справа без предупреждения  о  смещении  дробной ча-
сти. Например, 4.55 после усечения преобразуется в 4. Пере-
полнение имет  место, если  величина числовых данных превы-
шает  размерность объявленной  главной  переменной  вывода.
(Для SQLCODE устанавливается отрицательное число.)

Преобразование в значения с плавающей точкой: При  преобра-
зовании  числовых данных в данные с плавающей точкой проис-
ходит попытка подогнать  точность  и  размерность  числовых
данных  к точности и размерности главных переменных вывода.
Значащие цифры теряются, если число значащих цифр в главной
переменной вывода меньше,чем в действительном значении дан-
ного. Переполнение имеет место, если величина числовых дан-
ных превышает любое дробное и экспоненциальное значение об-
ъявленной главной переменной вывода. (Для SQLCODE  устанав-
ливается отрицательное число.) При переполнении  переменная
с плавающей точкой преобразуется в нуль.

Преобразование  в символьные значения: Когда преобразовыва-
ются числовые данные в символьные данные, ORACLE RDBMS пре-
образует число в символьную строку, смещаясь,если необходи-
мо,  вправо, ( стандартное  смещение  следующей  символьной
строки .)


Преобразование символьных данных

Если  символьные  данные транслируются в числовые значения,
ORACLE RDBMS вначале  осуществляет преобразование  числовых
данных, а затем займется указанными в предыдущих   разделах
преобразованиями  числовых  данных  в целое число или число
с плавающей точкой.


                            -63-


Если исходные символьные данные не преобразуются в числовые
SQLCODE устанавливаются в -1722.


Ошибки преобразования

Когда встречается  ошибка преобразования,  значение главной
переменной вывода не утверждается. Поэтому, если вы делаете
обработку ошибок   (для сравнениия с операторами WHEREVER),
вы должны всегда контролировать  SQLCODE  после  выполнения
операторов SQL.

Например, если значение данных велико для успешного  преоб-
разования  (как в случае, когда десятичное значение больше,
чем самое большое представленное целое), ORACLE RDBMS  воз-
вращает отрицательный код SQLCODE в SQLСА, идентифицирующий
ошибку переполнения числовых данных.



ЗАПРОСЫ, КОТОРЫЕ ВОЗВРАЩАЮТ НЕСКОЛЬКО СТРОК

Если запрос может возвращать более чем одну строку,  или вы
не знаете,  сколько строк будет возвращено,  вы должны  ис-
пользовать курсор   вместе  с оператором SELECT.  Следующие
разделы описывают применение курсоров.


ИСПОЛЬЗОВАНИЕ КУРСОРОВ

Курсором является  рабочая  область  памяти,   используемая
ORACLE и Pro*C для временного хранения результатов запроса.
Один (поименованный)  курсор ассоциируется с одним операто-
ром SELECT и может выполняться неоднократно  для  различных
вариантов запроса  (используя различные переменные связки).

Вначале необходимо объявить курсор ( связанный с запросом).
Затем использовать три выполняемых оператора SQL для  мани-
пуляции данными при помощи курсора.  Таким образом, сущест-
вует четыре команды курсора:

        *  DECLARE CURSOR

        *  OPEN CURSOR

        *  FETCH

        *  CLOSE CURSOR


                            -64-


После открытия курсора, используйте его для поиска множест-
ва строк, являющихся  результатом  связанного  с  курсором
запроса.  Все строки, удовлетворяющие критерию запроса, об-
разуют группу, называемую активной группой курсора.  Строки
активной  группы возвращаются одна за другой при их "выбор-
ке". Когда запрос выполнился, курсор "закрывается".

Нижний предел размера курсора определяется с помощью  опции
РСС AREASIZE. В версии 5.0 ORACLE, размер курсора распреде-
ляется  динамически  и  может автоматически регулироваться.
Для  определения  необходимого  размера   смотрите   раздел
"AREASIZE".


Оператор DECLARE CURSOR

Оператор DECLARE CURSOR определяет курсор, назначая его имя
и связывая его с запросом,  согласно следующему синтаксису:

    EXEC SQL DECLARE cursorname CURSOR FOR

    SELECT ... FROM ...

как в

    EXEC SQL DECLARE C1 CURSOR FOR
       select ename, empno, job, sal
       from emp
       where deptno = :deptno;

Оператор DECLARE CURSOR является  декларативным  оператором
SQL. Оператор  DECLARE CURSOR для объявления курсора должeн
помещаться перед любым другим оператором SQL,  связанным  с
этим курсором,  Pro*C не может интерпритировать обращение к
курсору, если он еще не объявлен. Возможности курсора явля-
ются дополнением   программ  на  Pro*C.  Однако,  операторы
(DECLARE, OPEN,  FETCH, CLOSE) должны размещаться все в од-
ной и той же прекомпиляторной единице.

Программа на Pro*C может объявлять столько курсоров, сколь-
ко запросов.  Каждый оператор DECLARE  CURSOR  должен  быть
уникальным, нельзя    объявить два курсора с одним и тем же
именем и в одной и той же программе,  даже  через  блоки  и
процедуры программы. Если вы будете пользоваться нескольки-
ми курсорами,  вы можете использовать опцию  MAXOPENCURSORS
при включении PCC (смотрите раздел "MAXOPENCURSORS").


                           -65-


Оператор OPEN CURSOR

При открытии курсора, оценивается запрос и идентифицируется
активная группа строк. Курсор открывается при  задании  вы-
полняемого оператора SQL:

    EXEC SQL OPEN cursorname;

как в

    EXEC SQL OPEN C1;

Главные переменные ввода во фразе WHERE, если их несколько,
оцениваются  посредством определения, какие строки удовлет-
воряют запросу (активная группа). Курсор помещается в поло-
жение  открыто  и  располагается сразу перед первой строкой
активной группы. Однако, ни одна из строк в действительнос-
ти не отыскивается в этой точке.  (Это будет сделано в опе-
раторе FETCH).

С тех пор, как вы открыли курсор, связанные с  ним  главные
переменные ввода не пересматриваются до тех пор, пока вы не
откроете курсор еще раз (и поэтому активная группа не будет
меняться).

Если вы не меняете действительный оператор SQL, связанный с
курсором (даже если вы изменили значения  переменных  связ-
ки), он  не будет вновь анализироваться после закрытия кур-
сора при его повторном открытии.  Однако, если вы после ма-
нипулирования с   другими  курсорами изменили оператор SQL,
связанный с определенным курсором,  то этот оператор  будет
повторно анализироваться после закрытия и повторного откры-
тия курсора.  Для изменения  некоторой  главной  переменной
ввода и,  таким образом,  и активной группы, вы должны пов-
торно открыть курсор.


Выборка строк из активной группы

Оператор FETCH  читает  строки  из активной группы и задает
имена переменным вывода,  содержащим результат.   Вспомним,
что оператор SELECT,  связанные с запросом,  могут не вклю-
чать фразу INTO, предпочтительнее фразу INTO и список глав-
ных переменных вывода включать в операторы FETCH. Синтаксис
выполняемого оператора FETCH:

    EXEC SQL FETCH cursorname INTO :hostvar1, :hostvar2 ...


                            -66-


как в

    EXEC SQL FETCH :pename, :pempno, :pjob, :psal;

Курсор  должен быть предварительно объявлен и открыт. Когда
FETCH начнет  выполняться,   курсор  переместится из места,
предшествующего  первой  строке  активной группы, к  первой
строке. Эта строка становится текущей строкой. Каждое   по-
следующее выполнение операции  FETCH  (выборки)  продвигает
курсор к следующей строке  в  активной  группе  ( измененяя
текущую строку). Курсор может продвигаться только вперед  в
активной группе. Возможен  только  один путь: возврат стро-
ки,  которая была предварительно выбрана,  закрытие  и  по-
вторное открытие  курсора и  начало  выборки вновь с первой
строки  активной группы. Если вы закроете курсор  после вы-
вода 9000 строк из 1000, вы должны вновь открыть курсор   и
повторить выборку.

Хотя вам необходимо выполнить операторы  выборки  несколько
раз, возможна    только  одна установка главных переменных,
связанных с FETCH. Если для открытого курсора выдается вто-
рой оператор FETCH с другими главными переменными, он игно-
рируется.

Если вы хотите изменить запрос, его  активную  группу,  или
какую-нибудь  главную  переменную ввода или вывода, вначале
измените переменную, затем закройте и вновь откройте курсор
и выполните FETCH.

Если активная группа является пустой, или содержит не боль-
ше строк, чем может быть выбрано,  устанавливается  SQLCODE
равный  +1403.  Для выполнения дальнейших операций с курсо-
ром, который возвращает код  +1403,  необходимо  закрыть  и
вновь открыть курсор.


Оператор CLOSE CURSOR

После  того,  как  вы осуществили выборку строк из активной
группы, вы должны закрыть курсор, чтобы освободить ресурсы,
полученные при открытии курсора. Курсор закрывается при за-
дании выполняемого оператора SQL:

    EXEC SQL CLOSE cursorname;

Никакая выборка не может быть осуществлена  после  закрытия
курсора,  т.к.  активная группа станет неопределенной. Если
вы вновь выполните выборку после закрытия  курсора,  ошибка


                            -67-


будет указывать на ошибочный курсор. Если необходимо  вновь
открыть курсор ( с другими значениями  главных  переменных,
например), просто повторно откройте курсор.


Оператор CURRENT OF CURSOR

Версия 1.1 программного интерфейса ORACLE обеспечивает син-
таксис SQL  для оператора CURRENT OF CURSOR,  используемого
при обращении к корректировке или удалению самой  последней
строки, выбранной  из одного курсора,  через другой курсор.
CURRENT OF CURSOR полностью  заменяет  применение  ROWID  в
операторе "SELECT FOR UPDATE".

    EXEC SQL DECLARE EMP_CUR CURSOR FOR
             SELECT ENAME,SAL
             FROM   EMP
             WHERE  EMPNO = :empno;
             FOR UPDATE OF SAL;

    EXEC SQL OPEN EMP_CUR;

    EXEC SQL FETCH EMP_CUR INTO :ename,:sal;

    EXEC SQL UPDATE EMP
             SET SAL=:new_sal
             WHERE CURRENT OF EMP_CUR;

CURRENT OF  CURSOR может использоваться только для последо-
вательной выборки.  Этот оператор эквивалентен  запоминанию
ROWID и его применению.


Типы курсоров

Хотя для большинства операций  Pro*C  необходимо  полностью
объявить все курсоры, для некоторых  других операций  Pro*C
будет создавать  курсоры  автоматически.  Понятие   курсора
применяется как в Pro*SQL, так и в Pro*C, и некоторое разъ-
яснение типов курсоров может оказаться полезным.

Для каждого оператора SQL,  в котором есть команда DML, DDL
или DCL,   Pro*C требует открытия Pro*C курсора.  Для Pro*C
требуется также курсор ORACLЕ для доступа  к  базе  данных.
(Число курсоров   ORACLE определяется в процессе выполнения
опцией Pro*C MAXOPENCURSORS.)  Требуется полностью объявить
все существующие курсоры только для операторов SELECT:  для
всех других команд DML (DDL и DCL),  Pro*C будет сама управ-
лять всеми вашими курсорами.


                            -68-



Итак, существуют следующие "типы" курсоров.

Полностью объявленные курсоры :  курсоры  Pro*C,  последова-
тельность которых объявляется в программе вместе с команда-
ми  курсора  и  служит для манипуляции результатами выборки
запроса. Например:

    EXEC SQL DECLARE CURSOR C1 ...

Безусловно открытые курсоры:  Последовательность  курсоров,
которые Pro*C получает в интересах пользователя, без дейст-
вий  со  стороны  пользователя.  Примером  являются курсоры
Pro*C, используемые для ввода, корректировки и выборки  од-
ной строки и т.д.

Курсоры  ORACLE:  Это  физические  курсоры. (Курсоры ORACLE
предпочтительнее чем курсоры Pro*C), которые требуются  для
выполнения каждой операции DML, DDL или DCL. Они  создаются
с  помощью  Pro*C, без каких-бы то ни было действий со сто-
роны пользователя.

Первые два типа курсоров (полностью объявленные и безуслов-
но открытые) всегда имеют  соответствующий  курсор  ORACLE.
Как  отмечалось ранее, MAXOPENCURSORS применяется для опре-
деления числа конкурирующих курсоров  ORACLE, которые могут
быть открыты одновременно. Если это число меньше, чем число
действительно требующихся  курсоров, Pro*C  будет  повторно
использовать уже существующий курсор. Однако, повторное ис-
пользование курсоров возможно только для безусловно  откры-
тых  курсоров; полностью объявленные курсоры всегда находя-
тся под управлением программы пользователя.

Эти  различия излишни для большинства пользователей, исклю-
чая тех, кому необходимо работать с более сложными  прогам-
мами, особенно, использующими как Pro*C, так и Pro*SQL.



ОБРАЗЦЫ ПРОГРАММ

Следующие примеры программ иллюстрируют применение курсоров
при выполнении запросов, возвращающих несколько строк.

Запрос, который содержит фразу WHERE

Первый пример высвечивает всех продавцов, их имена, оклад и
должность.


                            -69-



/* Пример #9 */
#include 

/ * ______________________________________________________

    Эта программа является примером программы на Pro*C, ко-
    торая  будет высвечивать всех продавцов в таблице  слу-
    жащих. Это пример того, как  работает  запрос,  возвра-
    щающий более чем одну строку.
_________________________________________________________* /

EXEC SQL BEGIN DECLARE SECTION;
        VARCHAR uid [20];
        VARCHAR pwd [20];
        float sal,comm;
        char ename[11];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
        /* логический вход в базу данных */
        strcpy(uid.arr,"SCOTT");
        /* скопировать имя пользователя  */
        uid.len=strlen(uid.arr);
        strcpy(pwd.arr,"TIGER");
        /* скопировать пароль            */
        pwd.len=strlen(pwd.arr);

        EXEC SQL WHENEVER SQLERROR STOP;
        EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

        printf("Connected to ORACLE user: %s \n",uid.arr);

        EXEC SQL DECLARE C1 CURSOR FOR
                 SELECT ENAME, SAL,COMM
                 FROM EMP WHERE JOB='SALESMAN';
        EXEC SQL OPEN C1;

        EXEC SQL WHENEVER NOT FOUND STOP;
        printf("SALESMAN NAME\t\tSALARY\t\tCOMMISSION\n\n");
        for (; ;)
        {
               EXEC SQL FETCH C1 INTO : ename,:sal,:comm;
               printf("%-10s\t\t%6.2f\t\t%6.2f\n",ename,sal,comm);

        }


                            -70-


                 EXEC SQL CLOSE C1;
        EXEC SQL WHENEVER SQLERROR CONTINUE;
        /* следуюшая ошибка не выбирается    */
        EXEC SQL COMMIT WORK RELEASE;
        /* логический выход из базы данных   */
                 exit(0);
        }


                            -71-


Более сложный запрос, использующий подсказки

В этом примере выдается подсказка для ввода  номера  отдела
и затем высвечиваются имена, работа  и оклад всех  служащих
в отделе,  упорядоченные по  выполняемой  работе и затем по
окладам.

/* Example #10 */
# include 

/* ________________________________________________________

   Эта программа является образцом программы на Pro*C,  ко-
   торая будет высвечивать имена, выполняемую работу и  ок-
   лады людей в заданном отделе, упорядоченные по работе  и
   окладам. Номер отдела запрашивается через подсказку.
___________________________________________________________ */

EXEC SQL BEGIN DECLARE SECTION;
        VARCHAR uid[20];
        VARCHAR pwd[20];
        float sal;
        int deptno;
        char job[10];
        char ename[10];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
        /* логический вход в базу данных   */
        strcpy(uid.arr,"SCOTT");
        /* скопировать имя пользователя    */
        uid.len=strlen(uid.arr);
        strcpy(pwd.arr,"TIGGER");
        /* скопировать пароль              */
        pwd.len=strlen(pwd.arr);


        EXEC SQL WHENEVER SQLERROR STOP;
        EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

        printf("Connected to ORACLE user: %s \n",uid.arr);

        printf("Enter department number: ");
        scanf("%d,&deptno);

        EXEC SQL DECLARE C1 CURSOR FOR
                SELECT ENAME,JOB,SAL
                FROM EMP WHERE DEPTNO=:deptno


                            -72-



                ORDER BY JOB,SAL;
        EXEC SQL OPEN C1;

        EXEC SQL WHENEVER NOT FOUND STOP;
              printf("EMPLOYEE NAME\t\tJOB\t\t\tSALARY\n\n");
              for (; ;)
{
              EXEC SQL FETCH C1 INTO :ename,:job,:sal;
              printf("%-10s\t\t%-10s\t%6.2f \n",ename,job,sal);
}
EXEC SQL CLOSE C1;
EXEC SQL WHENEVER SQLERROR CONTINUE;
/* следуюшая ошибка не выбирается    */
EXEC SQL COMMIT WORK RELEASE;
/* логический выход из базы данных   */
exit(0);
}


                            -73-




ГЛАВА 4. СОХРАНЕНИЕ И ОТКАТ РЕЗУЛЬТАТОВ РАБОТЫ

В этой главе определяется транзакция, или логическая едини-
ца работы,  которая может объединять  несколько  операторов
SQL вместе,  как одно целое.  Программист имеет возможность
написать программу так, что сможет контролировать когда ре-
зультаты работы транзакции программы будут сохраняться (де-
лать "фиксацию")  в базе данных,  или откатываться (  "сти-
раться" из базы данных).

В этой главе вы  изучите, как контролировать момент,  когда
изменения фиксируются в базе данных ORACLE. Поскольку глав-
ной особенностью ORACLE является то, что результаты не всех
действий фиксируются непосредственно в то же  время,  когда
вы их  получили; вы можете быть  уверены  в том,  что любая
транзакция заканчивается до того, как будет сохранен ее ре-
зультат. Другими словами, результаты работы  транзакции  не
фиксируются по частям.

ORACLE использует файл предварительного отображения (Before
Image file) для защиты содержимого базы данных. Файл  пред-
варительного отображения запоминает  в  памяти  блоки  базы
данных  в  том  виде, в каком они находяться перед запуском
транзакций. При определенных условиях, эти блоки  записыва-
ются в файлы базы данных без  изменений, которые только-что
были сделаны. Эти условия могут быть результатом:

       *  инициализированного пользователем  отката резуль-
          татов работы (ROLLBACK WORK)

       *  ненормального выхода  программы  пользователя  из
          ORACLE

       *  тупиковой ситуациии между различными процессами

       *  системной ошибки (технической или программной)

Ненормальное завершение процесса  пользователя  встречается
тогда, когда процесс неожиданно останавливается  при возни-
кновении программных  или  технических проблем, или при вы-
нужденном прерывании (таком как CTRL-T в системах VAX/VMS).
Успешное завершение встречается тогда, когда программа  по-
льзователя выполняется естественным путем,  закрывая курсо-
ры  и полностью сохраняя или откатывая результаты работы  и
возвращая управление пользователю.


                            -74-



ЛОГИЧЕСКИЕ ЕДИНИЦЫ РАБОТЫ

Логической единицей работы является последовательность опе-
раторов SQL,   которую ORACLE обрабатывает как простую сущ-
ность. Все операторы SQL обрабатываются совместно, они либо
одновременно фиксируются, либо одновременно не выполняются.
Например, логическая  единица работы может содержать добав-
ление некоторого   количества  денег на один счет (одна или
несколько операций INSERT) и вычитание некоторого количест-
ва денег с другого счета (вероятно,это операции INSERT, хо-
тя, может быть, и для различных таблиц). Если обе эти тран-
закции обрабатываются   в  одной  и  той же единице работы,
тогда нет опасности,  что база данных останется в  незавер-
шенном состоянии; обе транзакции либо сохраняют, либо отка-
тывают результаты работы одновременно.


Запуск единицы работы

Логическая единица работы безусловно начинается тогда, ког-
да встречается первый выполняемый оператор SQL (с одним вы-
ражением CONNECT). Выполняемые операторы всегда встречаются
внутри логической единицы работы,поэтому любой  выполняемый
оператор SQL,  исключая CONNECT,  которое встречается после
некоторой, уже завершенной, единицы работы, будет автомати-
чески стартовать   другую единицу работы.  В единицу работы
включаются только выполняемые операторы SQL;  декларативные
операторы, хотя   они и могут встречаться внутри логической
единицы работы,  не влияют на эту единицу работы.   Они  не
стартуют логическую единицу работы и н е должны встречаться
в ее пределах.


Завершение единицы работы

Как отмечалось выше, завершение единицы работы может иници-
ализироваться пользователем или системой, пользователь (или
прикладная  программа) может полностью фиксировать (COMMIT)
сделанные им  изменения  в базу  данных,  либо  отменить их
(ROLLBACK).  Время от времени два пользователя ORACLE будут
оспаривать одни и те же ресурсы и никто не сможет завершить
работу, пока кто-либо другой  не  освободит  некоторый  ре-
сурс.  Это называется тупиковой ситуацией и ORACLE, обнару-
живая ее, не выполняет работу одного из пользователей,  ос-
новываясь на определенных критериях. Если  возникла  техни-
ческая  или программная ошибка, ORACLE не  выполнит транза-
кции, активные в момент ошибки,  поэтому  никто  из  них не
оставит базу данных в незавершенном состоянии.


                            -75-


Для некоторых операторов SQL возможен автоматический COMMIT
при их успешном выполнении. Смотрите раздел "Сохранение ре-
зультатов работы".


Ресурсы, необходимые для выполнения единицы работы

Если в процессе выполнения операторов SQL программа получа-
ет блокировку, такие блокировки могут отменяться только при
сохранении результатов работы, закрытии курсора или при ло-
гическом выходе.   Когда используется SELECT ...FOR UPDATE,
полученные блокировки на уровне строк не отменяются до  тех
пор, пока  не закончится сохранение,  либо не будет выбрано
одно из двух действий.


СОХРАНЕНИЕ РЕЗУЛЬТАТОВ РАБОТЫ

Оператор COMMIT WORK завершает текущую  логическую  единицу
работы, если она задействована и сохраняет любые изменения,
сделанные в процессе выполнения этой единицы работы.   Син-
такси следующий:

    EXEC SQL COMMIT WORK [RELEASE]

Необязательный  параметр  RELEASE  освобождает все  ресурсы
(включая курсоры ORACLE), захваченные программой и осущест-
вляет логический выход из базы данных.

Вы должны всегда либо полностью сохранить,либо отменить ре-
зультаты  выполнения последней единицы работы в  программе,
используя опцию RELEASE. Не смотря на то, что  ORACLE будет
автоматически сохранять ждущие решения изменения  при успе-
шном завершении программы,  в случае ненормального заверше-
ния программы ORACLE сделает откат произведенных изменений.

Оператор COMMIT WORK не влияет на допустимые главные  пере-
менные или на управляющий поток программы.

Каждый оператор DDL (операторы, которые создают или уничто-
жают объекты базы данных,  такие,  как таблицы, индексы или
экранные формы)  завершается автоматическим сохранением ре-
зультатов работы.    Таким  образом,  COMMIT не требуется в
тексте операторов DDL.

Отметим, что логическа единица работы, задействованная тог-
да, когда   выполняется оператор DDL,  фиксирует результаты
своей работы перед выполнением DDL; таким образом,  незави-


                            -76-


симо от того,  успешно или нет завершился оператор DDL, ре-
зультаты работы предыдущей транзакции сохраняются.



ОТМЕНА РЕЗУЛЬТАТОВ РАБОТЫ

Оператор ROLLBACK WORD завершает текущую логическую единицу
работы, если  она задействованна и не выполняет никаких из-
менений, сделанных  в период работы этой единицы. Синтаксис
следующий:

    EXEC SQL ROLLBACK WORK [RELEASE]

Необязательный  параметр  RELEASE  возвращает  все  ресурсы
(включая курсоры ORACLE), захваченные программой и осущест-
вляет логический выход из базы данных.

Вы должны всегда полностью сохранять и отменять  результаты
выполнения последней единицы работы в программе,  используя
опцию RELEASE. Хотя ORACLE и будет  автоматически сохранять
ждущие решения результаты работы  при  успешном  завершении
программы,  в  случае  ненормального   завершения программы
ORACLE сделает откат изменений .

Оператор ROLLBACK WORK не влияет на допустимые главные  пе-
ременные или на управляющий поток программы.

Если при обнаружении ошибки или предупреждения вы использу-
ете принятый шаблон ROLLBACK WORK, а также используете фра-
зу WHENEVER, возможно зацикливание программы в том  случае,
если сама операция ROLLBACK завершается с ошибкой или  пре-
дупреждением. Вы можете  избежать  этого,  задав   WHENEVER
SQLERROR CONTINUE и WHENEVER SQLWARN  CONTINUE  перед пред-
ложением  ROLLBACK WORK.


ОПЦИЯ RELEASE

В предыдущих  разделах отмечалось,  что последний встретив-
шийся в программе оператор COMMIT WORK  или  ROLLBACK  WORK
должен использовать опцию RELEASE.  Если RELEASE не задает-
ся, то полученная при выполнении программы блокировка будет
сохраняться после завершения программы до тех пор, пока CLN
не узнает,  что процесс далее не будет активным. Это заста-
вит других   пользователей в среде с многими пользователями
ожидать получения заблокированных  ресурсов  или  завершить
свой процесс ошибочно.


                            -77-


ГЛАВА 5. ОБНАРУЖЕНИЕ ОШИБОК И ВОССТАНОВЛЕНИЕ


В  этой  главе вы изучите, как пользоваться SQLCA и индика-
торными переменными для обнаружения  и  воздействия на раз-
личные  условия,  такие, как  пустые  значения, безусловные
удаления, не возвращение ни одной строки, переполнение  или
усечение данных.


ИСПОЛЬЗОВАНИЕ ВОЗВРАЩАЕМЫХ ЗНАЧЕНИЙ В ИНДИКАТОРНЫХ
ПЕРЕМЕННЫХ

Как отмечалось ранее, каждая главная переменная может иметь
необязательные, связанные с ней, переменные:   индикаторные
переменные. Индикаторные переменные используются для наблю-
дения за особыми значениями полей:

       *  помещаются ли они в главной переменной без смеще-
          ния или начинаются с пустого значения

       *  являются ли значениями типа NULL

       *  смещаются ли из-за того,что возвращаемое значение
          шире, чем объявленный размер соответствующей гла-
          вной переменной

На рис. 5  представлены  возможные  значения,  которые  мо-
гут возвращаться индикаторной переменной.

       ____________________________________________________
       іВеличинаі                 Значение                і
       і________і_________________________________________і
       і 0      і Возвращаемое значение помещается в глав-і
       і        і ную переменную. Это значение не пустое иі
       і        і не было усечено.                        і
       і        і                                         і
       і -1     і Возвращаемое значение пустое(NULL). Зна-і
       і        і чение главной переменной неопределено.  і
       і        і                                         і
       і >0     і Возвращаемое значение было усечено. Ши- і
       і        і рина главной переменной была недостаточ-і
       і        і но. Действительное значение индикаторнойі
       і        і переменной равно ширине до смещения.    і
       і________і_________________________________________і

Рис. 5. Возможные значения индикаторной переменной


                            -78-



Использование индикаторных переменных и пустых значений

Изначальной  причиной  использования индикаторных  перемен-
ных  является применение их для манипуляции пустыми  значе-
ниями (NULL); в следующем разделе приведено несколько  при-
меров.

(Смотрите раздел "Индикаторные переменные" для более полной
информации по индикаторным переменным).


Исследование пустых значений

Отметим,  что  нельзя применять индикаторные переменные для
исследования условий (во фразе WHERE). Например:

       SELECT ... WHERE COMM = :PCOMM:PCOMMI

Эта фраза является ошибочной и будет возвращать отрицатель-
ный код sqlca.sqlcode. Корректный синтаксис:


SELECT ... WHERE COMM IS NULL


Ввод пустых значений

Индикаторные переменные могут применяться для введения зна-
чений  NULL. Вначале, в разделе DECLARE SECTION, определяют
2-х байтную переменную целого типа (в С это переменная типа
short). Затем, перед введением, устанавливают  индикаторные
переменные  равными -1 для тех колонок,  которые  вы хототе
определить как значения  NULL, как  показано  в   следующем
примере:

       ename = "clair" ;
       :icomm = -1 ;
       EXEC SQL insert into emp (ename, comm);
       values (:ename, :comm:icomm);

который является лучшим вариантом программы, чем:

       ename = "clair";
       EXEC SQL into emp (ename, comm);
       values (:ename, null);

потому, что NULL во втором случае является тяжелым кодом. В
первом случае, индикаторная переменная предварительно уста-


                            -79-


навливается в -1 (NULL), поэтому  значение  главной   пере-
менной неопределено.


Вывод пустых значений

Следующий код позволит программисту получать пустые  значе-
ния  и управлять их появлением. Отметим,  что  все  главные
переменные вывода  предполагаются  символьными  значениями,
исключая icomm.

       EXEC SQL select ename, sal, comm
       into :ename, :sal, :comm:icomm
       from emp
       where empno = :empno;
       if (icomm == -1)
         comm = "na/";
       printf(...



СТРУКТУРА SQLCA

SQLCA является структурой,  используемой каждой  программой
Pro*C для передачи информации о выполнении программы.  Нап-
ример, в  ней будет отмечено,  если оператор SQL  не  имеет
достаточного количества переменных для возврата необходимых
данных, поэтому  программист сможет откорректировать опера-
тор SQL.  В ней также будет определяться, в особенности для
транзакций, игнорировались  ли пустые значения, или измени-
лись ли данные с того момента, как стартовал запрос, поэто-
му программист сможет предупредить появление особых условий
для данных.

В  дистрибутивной  директории  ORACLE вы обнаружите образец
SQLCA (смотрите имя файла SQLCA, с таким же расширением как
и для исходных файлов на С для вашей  системы).  Вы  можете
всегда  использовать  EXEC SQL INCLUDE SQLCA  для включения
файлов, когда это необходимо. Вам нет необходимости  специ-
фицировать расширение имени файла. Размер SQLCA лимитирует-
ся  ограничениями  главного  языка. В С вы также можете ис-
пользовать одну глобальную область SQLCA и / или  несколько
локальных областей SQLCA.  Доступ  к  локальной SQLCA лими-
тируется ее размером или языком.

Если программа использует только одну структуру  SQLCA,  то
программисту  рекомендуется  скопировать из SQLCA некоторую
информацию, которую он предполагает сохранить или обращать-


                            -80-

ся к ней перед выполнением следующего  оператора  SQL.   (В
частности, он    может скопировать sqlca.sqlcode и элементы
sqlca.sqlwarm.)

Возможно включение SQLCA непосредственно в коде  программы,
что более   предпочтительно,   чем  использование оператора
INCLUDE SQLCA.  Если выпоступите так,  вы можете задать для
структуры любое имя.

Вы можете применять несколько областей SQLCA  в вашей про-
грамме,  например,  для сохранения  информации,  возвраща-
емой при выполнении транзакции (такой как ROW NOT FOUND),
вы должны  использовать  две области SQLCA, для двух раз-
личных структур, таких,  как "локальная переменная".  От-
метим, что в данный  момент используется только  одна об-
ласть SQLCA в Pro*C для  сохранения  или возвращения  ин-
формации.


Когда обращаться к SQLCA

SQLCA корректируется  после исполнения каждого выполняемого
оператора SQL; значение SQLCA является неопределенным после
декларативного оператора.   Поэтому осмотрительные програм-
мисты будут контролировать SQLCA только после  каждого  не-
декларативного оператора. В частности, необходимо контроли-
ровать SQLCA  после  каждого  оператора  DML,   потому  что
операторы INSERT и UPDATE могут завершаться неуспешно после
работы с некоторыми строками таблицы, в этом случае вы, ве-
роятно, должны  выполнить команду ROLLBACR WORK для восста-
новления базы данных в завершенном состоянии.

Используя оператор SQL WHENEVER можно обнаружить ненормаль-
ные условия и определить соответствующие действия,  основы-
ваясь на этих  условиях.   Поэтому  по  умолчанию  оператор
WHENEVER имеет вид:

       EXEC SQL WHENEVER anyerror CONTINUE;

Pro*C попытается завершить процесс не взирая на встреченные
ошибки. Рекомендуется  использовать оператор  WHENEVER  для
обнаружения ошибок и выполнения действий в точке их обнару-
жения.

Смотрите раздел "Оператор WHENEVER" где описывается предло-
жение WHENEVER и его опции.


                            -81-



Обозначение отдельных элементов SQLCA

Структура SQLCA в Pro*C показана на рис. 6.
__________________________________________________________
і    struct sqlca{                                       і
і              char            sqlcad(8);                і
і              long            sqlcac;                   і
і              long            sqlcode;                  і
і              struct          {                         і
і                   unsigned short sqlerrml;             і
і                   char           sqlerrmc[70];         і
і              } sqlerrm;                                і
і              char            sqlerrp[8]                і
і              long            sqlerrd[8]                і
і              char            sqlwarn[8]                і
і                char            sqlext[8]               і
і                                                        і
і    };                                                  і
і    struct sqlca sqlca;                                 і
і                                                        і
і________________________________________________________і

Рис. 6. Структура SQLCA

Отдельные  поля SQLCA описываются ниже. Отметим, что первые
два поля (sqlca.sqlcaid и  sqlca.sqlcabc)  уместны  впервую
очередь для языка FORTRAN, а не для С.

sqlca_sqlcaid  Символьная строка. Это поле инициализируется
       как "SQLCA" при распределении,  но только в том слу-
       чае, если оно применяется, как глобальная структура.

sqlca_sqlcabc Двоичное целое в 4 байта. Это поле устанавли-
       вается  для определения  длины,  в байтах, структуры
       SQLCA.

sqlca_sqlcadc 4-х байтное двоичное целое, в котором кратко
       излагаются результаты выполнения операторов SQL.

       нуль(zero)       определяет успешное завершение.

       положительное    определяет успешное выполнение с ко-
                        дом состояния. Распространен  толь-
                        ко положительный  код  1403 "строка
                        не найдена" или возвращена  послед-
                        няя строка.


                            -82-


       отрицательное    определяет ошибку в программе или в
                        системе. Если встречается фатальная
                        ошибка, программа не сделает попыт-
                        ки завершиться.   Возможные  ошибки
                        приведены  в руководстве "Сообщения
                        об ошибках ORACLE и коды".

sqlca_sqlerrm.sqlerrml      Содержит      длину      текста
       (sqlca.sqlerrm.sqlerrmc)

sqlca_sqlerrm.sqlerrmc  Символьная строка переменной длины,
       которая содержит текст ошибки, соответствующий номе-
       ру ошибки, указанной в sqlca.sqlcode.

sqlca.errp  Обычно не используется, это поле является  сим-
       вольной строкой.

sqlca_sqlerrd  Это область из 6-ти 4-х байтных двоичных це-
       лых, используемых для описания внутреннего состояния
       RDBMS ORACLE. Обычно используется только третий эле-
       мент [2];   он определяет число  строк, обработанных
       для операций DML, таких как  INSERT или UPDATE. Эле-
       менты 0, 1, 3, 4 и 5 обычно не используются.

sqlca_sqlwarn  Подструктура, содержащая восемь односимволь-
       ных  элементов.  Эти элементы действуют, как  преду-
       преждение при  различных  ситуациях,  которые  могут
       встречаться в процессе прекомпиляции. Например, пре-
       дупреждение устанавливается, когда ORACLE игнорирует
       пустое значение в вычислении среднего. Если установ-
       лено предупреждение, значение элемента  устанавлива-
       ется в "W"; в противном случае значение элемента пу-
       стое. Если установлено одно или несколько предупреж-
       дений, первый элемент, sqlca.sqlwarn[0] всегда уста-
       навливается в "W".

       Описание  каждого элемента sqlca.sqlwarn следует да-
       лее. Отметим, что восемь элементов  идентифицируются
       как элементы от [0] до [7].

sqlca_sqlwarn[0] Если sqlca_sqlwarn[0] пустой элемент,   то
       предупреждение для  некоторого оператора не устанав-
       ливается. Если  для sqlca_sqlwarn[0] устанавливается
       в "W", то при этом устанавливается одно или несколь-
       ко предупреждений,  которые  необходимо  контролиро-
       вать. "W"  никогда не обозначает тяжелую ошибку,  но
       каждо такое предупреждение должно обратить  внимание
       программиста на   определенные проблемы или условия,
       которые желательно контролировать.


                            -83-


sqlca_sqlwarn[1] Если второй элемент sqlca_sqlwarn[1] уста-
       навливается в "W", то одно  или  более  возвращаемых
       символьных полей были усечены,  потому что объявлен-
       ная ширина главных  переменных  была  недостаточной.
       Это относится только к  символьным  данным;  ORACLE
       усекает определенные числовые данные без выдачи пре-
       дупреждения  или  возврата отрицательного  значения
       sqlca_sqlсode.

       Для определения, какие  поля  усечены  и  насколько,
       вы  должны  обратиться к индикаторным переменным для
       возвращаемых данных.  Если  индикаторная  переменная
       положительная,  ее  значение равняется длине  данных
       перед усечением (и ширина главной переменной  должна
       увеличиться соответственно).

sqlca_sqlwarn[2]  Третий  элемент  sqlca_sqlwarn показывает
       условие, которое хотя не ведет к неизбежной  ошибке,
       может оказаться полезным программисту.

       Если  устанавливается "W", то sqlca_sqlwarn[2] опре-
       деляет, что при вычислении функции были игнорированы
       одно или более пустых значений  (таких  функций  как
       AVG,  SUM,  MIN,  MAX). Если необходимо, программист
       может пожелать использовать функцию  NVL  -  функцию
       пустых  значений  для временного присвоения значений
       для данных типа NULL (например  временное присвоение
       всем пустым значениям значения нуль).

sqlca_sqlwarn[3] Если  четвертый  элемент  sqlca_sqlwarn[3]
       устанавливается в "W", это означает, что число ячеек
       в списке SELECT не равно числу главных переменных во
       фразе  INTO.  Хотя данные и  возвращаются, их  число
       равно меньшему из двух значений.

sqlca_sqlwarn[4] Если пятый элемент,  sqlca_sqlwarn[4], ус-
       танавливается в "W",  то либо оператор UPDATE,  либо
       DELETE написано без фразы WHERE,  что означает,  что
       каждая строка   таблицы  будет  изменена или удалена
       (иногда) это  называют  безусловным  изменением  или
       удалением, потому, что нет фразы WHERE, используемой
       для ограничения строк,  которые  корректируются  или
       удаляются). Так как это более общий случай, по срав-
       нению с удалением или  корректировкой  одной  строки
       или группы строк,  ORACLE выдает предупреждение, так
       что можно будет обнаруженное  некорректное  удаление
       или корректировку либо утвердить,либо дать им откат.


                            -84-

sqlca_sqlwarn[5]  Шестой  элемент, sqlca_sqlwarn[5], обычно
       не используется.

sqlca_sqlwarn[6] Седьмой элемент,  sqlca_sqlwarn[6],  уста-
       навливается в "W",  если только что выполненое пред-
       ложение SQL  предлагает ORACLE откат результатов ло-
       гической единицы работы.  Отметим,  что этот элемент
       не устанавливается   после  оператора ROLLBACK WORK,
       скорее он устанавливается,  когда откат  результатов
       работы был   безусловным.  Например sqlca_sqlwarn[6]
       устанавливается в "W",  когда происходит откат тран-
       закции при время тупиковой ситуации.

sqlca_sqlwarn[7] Восьмой элемент sqlca_sqlwarn[7] устанав-
       ливается в "W",если текущие данные строки отличают-
       ся  от  состояния данных во время запроса (или были
       удалены после того, как стартовал запрос). Он уста-
       навливается при возврате из  выборки, в том  случае,
       если колонки, появляющиеся в запросе и принадлежащие
       таблице, указанной во фразе  FOR UPDATE,  изменились
       между временем  стартинга запроса и временем,  когда
       строка была выбрана и заблокирована. Для того, чтобы
       установить  это предупреждение, колонки должны  быть
       указаны  в  списке SELECT запроса и принадлежать та-
       блице, имя которой указано во фразе FOR UPDATE.

       Этот элемент не совместим с SQL/DS, а также DB2, ко-
       торые не имеют таких свойств. Если пользователи  хо-
       тят  сохранить  совместимость с этими системами, они
       не должны использовать этот элемент.

sqlca_sqlext Последнее поле SQLCA, sqlca_sqlext  обычно  не
       используется. (Он предназначен для возврата символь-
       ной строки).


ОПЕРАТОР  WHENEVER

Оператор WHENEVER  является  необязательным   декларативным
оператором, который если используется, то определяет, какие
действия будут выполнены в случае обнаружения ошибки.  Ваша
программа может содержать прямые ссылки на часть SQLCA, ли-
бо может использовать  операторы  WHENEVER.   Использование
операторов WHENEVER вообще является более легким и предпоч-
тительым, потому  что с помощью WHENEVER  можно  установить
контроль там, где точный контроль невозможен (смотрите раз-
дел "WHENEVER в сравнении с точным контролем ошибок").


                            -85-


WHENEVER обнаруживает  ошибки  посредством  контроля  SQLCA
после каждого выполняемого оператора SQL.   WHENEVER  может
использоваться для    обнаружения  ошибок  ORACLE  (которые
представлены в обзоре сообщений об ошибках и кодах),   пре-
дупреждений Pro*C  (таких как усечение поля или использова-
ние пустых значений в функциях) и конца условий выборки.


Синтаксис операторов WHENEVER

Синтаксис для WHENEVER представлен на рис. 7.
___________________________________________________________
іEXEC SQL WHENEVER [SQLERRORіSQLWARNINGіNOT FOUND         і
і                  [STOP    іCONTINUE  іGO TO stmt-label];і
і_________________________________________________________і

Рис. 7. Синтаксис оператора WHENEVER

где:

SQLERROR устанавливается, когда sqlca.sqlcode отрицателен.

SQLWAARNING устанавливается, когда sqlca.warn[0] устанавли-
       вается в "W".

NOT FOUND устанавливается, когда sqlca.sqlcode равен  +1403
       ("строка не найдена")

STOP  вызывает завершение программы. Логическая единица ра-
       боты откатывается.

CONTINUE игнорирует состояние sqlca и  вызывает  выполнение
       следующей по списку программы.

GO TO (или GOTO)  вызывает управление переходом к предложе-
       нию, указанному меткой. Метка может содержать не бо-
       лее 18 символов.

По  умолчанию программа на Pro*C будет продолжаться , когда
она столкнется с одним из трех условий:  отрицательный  код
sqlca.sqlcode,   установка  "W"  для  sqlca_sqlwarn[0]  или
sqlca.sqlcode.


Изменение в поведении NOT FOUND

Начиная работу с версией V 1.0.5, поведение NOT FOUND  сов-
местимо  с  продуктом  IBM DB2. Это означает, что NOT FOUND
устанавливается для обоих операторов:


                            -86-


  EXEC SQL DELETE EMP            EXEC SQL UPDATE EMP
           WHERE ...                      SET
                                          WHERE ...

когда нет строк, удовлетворяющих условию  во  фразе  WHERE.
Чтобы  сделать это более наглядным будет выдаваться сообще-
ние об ошибке "END OF FETCH" - "Конец выборки" или "NO DATA
FOUND" - "Данные не найдены".

ПРЕДУПРЕЖДЕНИЕ: Эта  новая функция NOT FOUND означает,  что
некоторая программа,    которая  некорректно   обрабатывает
WHENEVER NOT  FOUND будет завершаться неуспешно.  Например,
Следующее действие завершиться неуспешно из-за  перехода  к
бесконечному циклу, если фраза WHERE в операторе DELETE вы-
зовет установку NOT FOUND:

       EXEC SQL WHENEVER NOT GO TO 200
  100  CONTINUE
       EXEC SQL FETCH C INTO  ...
       GO TO 100

  200  CONTINUE
       EXEC SQL DELETE EMP WHERE  ...


Сфера действия оператора WHENEVER

Поскольку оператор WHENEVER является декларативным операто-
ром, сфера  его действия определяется физической позицией в
коде, независимо  от местонахождения в текущей логике. Пре-
компилятор генерирует код при одиночном  прохождении  через
исходную программу.


WHENEVER в сравнении с точным контролем ошибок

Вы можете установить точный контроль SQLCA с целью просмот-
ра кодов ошибок или установленных предупреждений. Вы можете
использовать это в добавление  к  использованию  операторов
WHENEVER или вместо их использования.

Применение одной  из опций,  CONTINUE или GOTO в операторах
WHENEVER является более предпочтительным, чем использование
опции STOP. Хотя STOP и является действительной опцией, ис-
пользование которой означает, что программа просто заверше-
ловков, ни итогов или какой-нибудь другой обратной   связи.
на, при этом не выдается ни финальных сообщений, ни заго


                            -87-


Оператор WHENEVER  должен  предшествовать  тем  выполняемым
операторам SQL, которые вы хотите тестировать. Для примера,
смотрите рис. 8.
___________________________________________________________
і EXEC SQL WHENEVER SQLERROR GOTO  labx;                  і
і         ...                                             і
і labx:  printf ("Program terminated. SQLCODE is:         і
і                 %d/n",sqlcode);                         і
і EXEC SQL WHENEVER SQLERROR CONTINUE;                    і
і EXEC SQL ROLLBACK WORK RELEASE;                         і
і exit(1);                                                і
і_________________________________________________________і

Рис. 8. Применение WHENEVER и пример  полного  контроля
ошибок

На  рис. 8,  управление  передается  по  метке "labx", если
встречается состояние SQLERROR. Затем программа высвечивает
sqlcode (отрицательное число, определяющее ошибку  ORACLE),
откатывает логическую единицу работы и завершает программу.
Оператор WHENEVER SQLERROR CONTINUE используется  для  пре-
дотвращения зацикливания программы, являющегося результатом
ошибочного выполнения ROLLBACK WORK.

Полный контроль   ошибок   делается  после  каждого  вызова
ORACLE, либо если используется оператор WHENEVER, либо если
контроль области  SQLCA включен непосредственно в код прог-
раммы.


ОБРАЗЦЫ ПРОГРАММ

Следующая программа выполняет запрос:

  SELECT * FROM EMP

и демонстрирует контроль некоторых ошибок.

/* Пример #11 */
# include 
/*=========================================================
       Эта программа является примером Pro*C программы, ко-
       торая осуществляет  контроль ошибок.  Будут высвечи-
       ваться колонки из таблицы служащих и если встретятся
       некоторые ошибки, будут определены  действия,  кото-
       рые будут выполнены при этом.
=========================================================*/


                            -88-


EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR uid[20];
       VARCHAR pwd[20];
       int empno;
       char ename[10];
       char job[10];
       int mgr;
       char hiredate[9];
       float sal;
       float comm;
       int deptno;
       short empnoi,enamei,joib,mgri,hiredatei,sali,commi,deptnoi;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main( )
{
       /* логический вход в  ORACLE */
       strcpy(uid.arr,"SCOTT");
       /* скопировать имя пользователя */
       uid.len=strlen(uid.arr);
       strcpy(pwd.arr,"TIGGER");
       /* скопировать пароль           */
       pwd.len=strlen(pwd.arr);

       EXEC SQL WHENEVER SQLERROR GOTO errprt;
       EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

       printf("Connected to ORACLE user: %s \n",uid.arr);

       EXEC SQL DECLARE C1 CURSOR FOR
               SELECT EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO
               FROM EMP;
       EXEC SQL OPEN C1;

       printf("EMPNO    EMPLOYEE   JOB    MGR\n");

       printf("   HIDATE      SAL       COMM     DEPTNO\n")

       EXEC SQL WHENEVER NOT FOUND GOTO finish;
       for ( ; ; )
       {
          EXEC SQL FETCH C1 INTO :empno:empnoi,:enamei,:job
              :jobi,:mgr:mgri,:hiredate:hiredatei,:sal:sali,
              :comm:commi,:deptno:deptnoi;
          if (empnoi) empno = -1;
           /*пустое значение не найдено*/


                            -89-


          if (enamei) ename = "";
           /*пустое значение не найдено*/
          if (jobi) job = "";
           /*пустое значение не найдено*/
          if (mgri) mgr = -1;
           /*пустое значение не найдено*/
          if (hiredatei) hiredate = "";
           /*пустое значение не найдено*/
          if (sali) sal = -1;
           /*пустое значение не найдено*/
          if (commi) comm = -1;
           /*пустое значение не найдено*/
          if (deptnoi) deptno = -1;
           /*пустое значение не найдено*/
          printf("%5d   %-10s   %-9s %5d\n",
             empno,ename,job,mgr);
          printf("   %9s    %6.2f   %6.2f    %5d\n",
             hiredate,sal,comm,deptno);

}

finish:
printf("\n select completed. \n");
EXEC SQL CLOSE C1;
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL COMMIT WORK RELEASE;
/* логический выход из ORACLE */
exit(0);
errprt:

printf("\n %.70s \n",sqlca.sqlerrm.sqlerrms);
EXEC SQL ROLLBACK WORK RELEASE;
/* логический выход из ORACLE */
exit(1);
}



                            - 89 -




ГЛАВА 6. ДИНАМИЧЕСКИ ОПРЕДЕЛЯЕМЫЕ ОПЕРАТОРЫ
ННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН


     В этой главе освещена развитая техника  программирования,
которая  полезна  для  написания  гибких программ,  но требует
большего понимания программистом кодирования в С и языке SQL.
     Начинающие пользователи PRO*C должны либо пропустить либо
бегло прочесть эту главу.
     Большинство прикладных программ разработаны с учетом спе-
циальных использований:  например,  изменение служебных данных
введением  полного  служебного  имени  или  введением данных и
транзакцией этих данных.  В этом случае, природа или "структу-
ра"  этой  транзакции  может  быть  предопределена  в  большой
экстент;  в этом случае программист знает  чьи  таблицы  могут
быть изменены,  чьи поля необходимы для вводов или замен и ка-
ковы их типы данных и ограничения.
     Однако, некоторые  прикладные  программы могут предпочти-
тельно быть способными для принятия и выполнения многих  типов
операторов SQL,  независимо от того,  являются ли они простыми
DELETES или UP- DATES или более комплексными запросами. В этих
случаях программист хочет быть способным дать программе допуск
к любому действующему оператору SQL, вводимому во время выпол-
нения, и выполнить его. Очень возможно, что ни оператор SQL ни
его структура не будут известны программе.  Например, простей-
шая  программа PRO*C может требовать от пользователя служебные
номера для записей,  необходимые для того,  чтобы их заменить.
Программа  PRO*C,  которая  включает  динамически определяемый
оператор SQL,  может просто запросить оператор SQL,  будет это
INSERT,  CREATE,  SELECT или любой иной и после некоторой про-
верки, выполнит эту транзакцию. Таким образом, динамически оп-
ределяемые операторы дают программистам и конечным пользовате-
лям много большую гибкость,  с которой их программы могут быть
выполнены.
     Динамический SQL может быть использован для конструирова-
ния  оператора  SQL  из  текстовой цепочки символов,  вводимой
пользователем.  Использование этой формы динамического SQL  не
требует от пользователя знания SQL,  но однако допускает иметь
точную структуру оператора SQL до времени выполнения.



ОПРЕДЕЛЕНИЕ ДИНАМИЧЕСКИ ОПРЕДЕЛЯЕМЫХ ОПЕРАТОРОВ
--------------------------------------------Д

     Динамически определяемые  операторы  являются операторами
SQL, которые неизвестны во время компиляции; этот оператор мо-
жет и вероятно будет изменен от исполнения к исполнению.
     Как при кодировании "статических" операторов SQL в  прог-
раммах PRO*C, операторы SQL SELECT -- особенно те, что возвра-
щают более одной строки -- отчасти более сложны для  кодирова-
ния чем операторы SQL, которые просто сообщают об успешном вы-
полнении или неудаче.


                            - 90 -


ТИПЫ ДИНАМИЧЕСКИ ОПРЕДЕЛЯЕМЫХ ОПЕРАТОРОВ
--------------------------------------------Д

     Эта глава обращается к четырем путям программирования ди-
намических операторов в Вашей программе. Четыре метода обобща-
ются на рисунке 9, на cтранице 87.

Ъ--------------------------------------------------------------ї
і Метод 1: Использование оператора EXECUTE IMMEDIATELY         і
і  Прекомпилирует любой оператор SQL (исключая SELECT) и выпол-і
і  няет его. Оператор SQL может быть буквенным или host-пере-  і
і  менной. Он может содержать любую host-переменную (ни входныхі
і  ни выходных host-переменных)                                і
і                                                              і
і Метод 2: Использование операторов PREPARE и EXECUTE          і
і  Берет любой оператор SQL (исключая SELECT'ы) и выполняет егоі
і  Этот оператор может содержать входные или выходные host-пе- і
і  ременные. Все-таки он может быть использован снова для "лю- і
і  бого" оператора SQL, и число переменных и соответствующие   і
і  типы данных должны быть всегда одними и теми же.            і
і                                                              і
і Метод 3: Использование операторов PREPARE и FETCH            і
і  Допускает использование SELECT'ов. Оператор может содержать і
і  входные или выходные host-переменные. Последовательность дляі
і  этого метода следующая:                                     і
і  PREPARE, DECLARE, OPEN, FETCH.                              і
і  Число переменных и их соответствующие типы данных должны    і
і  всегда соответствовать.                                     і
і                                                              і
і Метод 4: Использование дескрипторов Bind и Define            і
і  Допускает использование любого оператора SQL, включая прос- і
і  тые и многострочные SELECT'ы.                               і
і                                                              і
А--------------------------------------------------------------Щ

Рис.9. Методы программирования динамических операторов SQL

     В то время как первые три месяца концептуально проще, они
накладывают некоторые ограничения на программиста и  пользова-
теля.  Четвертый метод допускает большую гибкость,  но требуют
большего понимания концепций ORACLE со стороны программиста.
     Простейшие случаи   динамически  определяемых  операторов
возникают тогда,  когда оператор SQL возвращает никаких других
значений  кроме "успех" или "неудача".  Это включает операторы
DDL и DCL и все команды DML,  исключая SELECT'ы.  Примеры этих
команд следующие:

          CREATE TABLE
          DROP INDEX
          UPDATE table SET column = value
          GRANT SELECT ON table TO username
          REVOKE CONNECT FROM username

     Каждый раз  только один результат является набором значе-
ний в SQLCA,  который просто указывает,  удалась или  нет  эта
операция.
     Кодирование динамических операторов SELECT более  сложно,
поскольку "форма" результата (число возвращенных столбцов,  их
типы данных и максимальная ширина) заранее неизвестна для каж-
дого оператора DDL.


                            - 91 -



ПРИНЯТИЕ ВВОДА ДЛЯ ДИНАМИЧЕСКИХ ОПЕРАТОРОВ SQL
--------------------------------------------Д


     PRO*C требует следующее для оператора,  вводимого как ди-
намический оператор SQL:

     * Он не должен содержать любые предограничители (delimiters)
       языка host.
     * Он недолжен быть префиксирован с помощью EXEC SQL.
     * Он должен содержать переменные языка host.


     Например, следующее неправильно:

          s = "EXEC SQL DELETE...";
          EXEC SQL EXECUTE IMMEDIATE :s;

     поскольку задание  переменной s включает предограничители
языка host "EXEC SQL".


     Переменная, содержащая оператор SQL, вводится динамически в
то время, как программа PRO*C содержит параметры, как в:

          DELETE FROM EMP WHERE EMPNO = :PEMPNO

     Если динамический оператор не содержит и не является зап-
росом,  то затем оператор EXECUTE IMMEDIATELY прекомпилирует и
запустит  его  на  выполнение  (смотри   "Метод   1:   EXECUTE
IMMEDIATELY").  Если динамический оператор содержит параметры,
он требует использования двух операторов:  PREPARE  и  EXECUTE
(смотри "Метод 2: PREPARE и EXECUTE").



Замечания по использованию операторов DDL
--------------------------------------------Д

     Версия 1.0 интерфейсов с языками программирования  ORACLE
подсвечивает  позицию  курсора при каждом выполнении оператора
DDL (таком как CREATE TABLE). Это имеет следующие результаты:

     * Программы, которые используют временные таблицы (выпол-
       нением CREATE,  INSERT и DROP в довольно быстрой после-
       довательности) могут сейчас успешно выполнять  операцию
       DROP  таблицы,  тогда  как в версии 4 ORACLE Вы увидите
       следующее сообщение:

           DDL operation and resource not available

       поскольку на таблице будет однако висеть замок  грамма-
       тического разбора.

     * Если Вы смешиваете операторы DDL с операторами DML,  Вы
       можете заметить некоторое замедление выплнения,  приво-
       дящее к посветке позиции курсора.


                            - 92 -

МЕТОД 1: EXECUTE IMMEDIATE
--------------------------------------------Д

     Чтобы прочесть,  прекомпилировать и выполнить оператор Вы
можете   использовать   выполнимый   оператор  SQL  -  EXECUTE
IMMEDIATE,  за которым следует либо литерал  либо  переменная,
содержащая оператор SQL для выполнения.  Например, смотри сле-
дующие примеры EXECUTE IMMEDIATE:

     EXEC SQL BEGIN DECLARE SECTION;
       VARCHAR dstring [80];
       . . .
     EXEC SQL END DECLARE SECTION;
     if scanf("%s",dstring);

     EXEC SQL EXECUTE IMMEDIATE :dstring;

     Обратите внимание на то, что DSTRING не является перемен-
ной  host'а;  и  не  ключевое  слово.  Альтернативно Вы можете
использовать литералы цепочек символов:

EXEC SQL EXECUTE IMMEDIATELY "DELETE FROM EMP WHERE EMPNO=9251";

     Альтернативно Вы могли бы закодировать оператор DELETE  в
программе:

          scanf("%d", &PEMPNO);
          while (PEMPNO != 0)
            {
             EXEC SQL DELETE FROM EMP WHERE EMPNO = :PEMPNO;
             scanf("%d", &PEMPNO);
            }

в этом случае оператор оператор DELETE,  будет выполняться не-
однократно, до тех пор, пока не вводится PEMPNO 0.



Пререквизиты для EXECUTE IMMEDIATE
--------------------------------------------Д

     Для выполнения EXECUTE IMMEDIATELY следующее должно  быть
верно:

     *   Оператор SQL не может быть запросом.
     *   Оператор SQL не может сожержать переменной host'a.



Ограничения EXECUTE IMMEDIATE
--------------------------------------------Д

     Оператор EXECUTE  IMMEDIATE  может  быть  выполнен только
исключительно с единственным параметром.
.


                            - 93 -


Пример EXECUTE IMMEDIATE
--------------------------------------------Д

/* Пример #12 */
#include 

/*=========================================================
     Эта программа является примером PRO*C, который
     будет запрашивать конструкцию WHERE для использования
     в операторе update. Это предназначено для использования
     с EXECUTE IMMEDIATE
=========================================================*/
EXEC SQL BEGIN DECLARE SECTION;
        VARCHAR uid[20];
        VARCHAR pwd[20];
        char select[132];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
    char where[80];
    int scode;

    /* log into ORACLE */
    strcpy(uid.arr,"SCOTT);    /* copy the user name */
    uid.len=strlen(uid.arr);
    strcpy(pwd.arr,"TIGER");   /* copy the password */
    pwd.len=strlen(pwd.arr);

    EXEC SQL WHENEVER SQLERROR STOP;
    EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

    printf("Connected to ORACLE user: %s \n",uid.arr);

    strcpy(select,"UPDATE EMP SET COMM = 100 WHERE ");
    printf("Please enter where clause for the following:\n");
    printf("%s",select);
    scode =scanf("%s",where);
    if (scode == EOD !! scode == 0)
    {
            printf("Invalid entry. \n");
            exit(1);
    }
    strcat(select,where);

    EXEC SQL EXECUTE IMMEDIATE :select;

    printf("%d records updated. \n",sqlca.sqlerrd[2]);
    EXEC SQL WHENEVER SQLERROR CONTINUE;/*don't trap errors*/
    EXEC SQL COMMIT WORK RELEASE;       /*log off database */
    exit(0);
}
.


                            - 94 -



МЕТОД 2: ИСПОЛЬЗОВАНИЕ PREPARE И EXECUTE
--------------------------------------------Д

     Два оператора  PREPARE  и  EXECUTE  выполняются,  как   и
EXECUTE  IMMEDIATE,  в  два шага.  Попытка выполнить PREPARE и
EXECUTE таково,  что оператор SQL грамматически  анализируется
(подготавливается)  только  однин раз,  но может быть выполнен
число раз,  задаваемое числом.  Таким  образом,  с  PREPARE  и
EXECUTE  оператор  SQL может содержать host-переменную,  тогда
как с EXECUTE IMMEDIATE оператор SQL этого не может.

     Рассмотрим снова пример оператора SQL,  который  содержит
входную host-переменную, PEMPNO:

     DELETE FROM EMP WHERE EMPNO = :PEMPNO

     Оператор PREPARE  делает две вещи:  он проводит граммати-
ческий анализ (прекомпилирует) оператор SQL и дает имя  опера-
тора оператору SQL.  (Заметьте,  что это имя не является host-
переменной,  также как им не является  имя  курсора.)  Однако,
оператор должен быть объявлен как host-переменная.

     scanf("%s", &DSTRING)
     EXEC SQL PREPARE S1 FROM :DSTRING;

     Оператор EXECUTE выполняет этот оператор уже  прекомпили-
рованным,  используя те переменные, что поставляемыми для каж-
дого параметра (этот  пример  использует  уже  один  параметр,
PEMPNO). Для использования более чем одного параметра, исполь-
зуйте формат USING :VAR1, :VAR2,...

     scanf("%d", &PEMPNO)
     while (PEMPNO !=0)
     {
       EXEC SQL EXECUTE S1 USING :PEMPNO;
       scanf("%d", &PEMPNO);
     }

     PREPARE выполняется  над  оператором SQL только один раз,
но он выполняется (EXECUTE) так часто как нужно,  с тем же са-
мым  логическим  устройством  действия (logical unit of work).
Если эта текущая транзакция  сблокирована  или  возвращена,  и
оператор  SQL должен быть выполнен заново (выполнено EXECUTE),
оператор должен быть подготовлен (PREPARE) снова.



Ограничения на PREPARE и EXECUTE
--------------------------------------------Д


     Для использования PREPARE и EXECUTE число параметров и их
типы данных должны быть известны,  также как входная host- пе-
ременная должна быть объявлена в разделе DECLARE. В предыдущем
примере  только  операторы SQL,  использующие одну переменную,
которая известно,  что должна быть целочисленной,  могут  быть
успешно введены.  Оператор SQL не может быть запросом.  Напри-
мер, все следующее может быть успешно выполнено:


                            - 95 -

     INSERT INTO DEPT (DEPTNO) VALUES ( :DEPTNO);
     UPDATE DEPT SET ENAME = 'SALES' WHERE DEPTNO = :DEPTNO;
     UPDATE DEPTNO SET LOC = :LOC;


Пример PREPARE и EXECUTE
--------------------------------------------Д

     Тот пример,  что следует далее, демонстрирует использова-
ние PREPARE и EXECUTE


/* Пример #13 */
#include 

/*==========================================================
   Эта программа является примером PRO*C, который запросит
   конструкцию WHERE для использования в операторе update.
   Оператор UPDATE включает связанную переменную для COMM.
   Этот пример использует PREPARE и EXECUTE.
===========================================================*/
EXEC SQL BEGIN DECLARE SECTION;
        VARCHAR uid[20];
        VARCHAR pwd[20];
        float comm;
        char select[132];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
   char where[80];
   int scode;

   /* log into ORACLE */
   strcpy(uid.arr,"SCOTT");         /* copy the user name */
   uid.len=strlen(uid.arr);
   strcpy(pwd.arr,"TIGER");         /* copy the password */
   pwd.len=strlen(pwd.arr);

   EXEC SQL WHENEVER SQLERROR GOTO errrpt;
   EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

   printf("Connected to ORACLE user: %s \n",uid.arr);

   strcpy(select,"UPDATE EMP SET COMM=:comm WHERE ");
   printf("Please enter where clase for the following: \n");
   printf("%s",select);
   scode = scanf("%s",where);
   if (scode == EOF !! scode == 0)
   {
           printf("Invalid entry. \n");
           exit(1);
   }

   strcat(select,where);

   EXEC SQL PREPARE S1 FROM :select;

   printf("Please enter commission:    ");
   scanf("%f",&comm);


                            - 96 -

   EXEC SQL EXECUTE S1 USING :comm;

   printf("\n %d records updated. \n",sqlca.sqlerrd[2]);
   EXEC SQL WHENEVER SQLERROR CONTINUE;/*don't trap errors*/
   EXEC SQL COMMIT WORK RELEASE;       /*log off database */
   exit(0);

errrpt:
   printf(2\n %d.70s \n",sqlca.sqlerrm.sqlerrmc);
   EXEC SQL ROLLBACK WORK RELEASE;      /*log off database*/
   exit(1);
}




МЕТОД 3: PREPARE, OPEN И FETCH
--------------------------------------------Д


     Метод 3  проще  для  использования PREPARE и EXECUTE,  но
позволяет большую желаемую  гибкость  использования  запросов.
Если  оператор SQL для выполнения является запросом,  тогда Вы
должны использовать либо Метод 3 либо  4.  Метод  3  допускает
использование препрограммированных или нединамических запросов
-- то есть запросы,  чей список SELECT известен и может следо-
вательно быть запрограммирован,  но чей критерий поиска (как в
конструкции WHERE) или порядок (конструкция  ORDER  BY)  могут
изменяться.

     Метод 3 включает пять шагов:

     PREPARE FROM 
     DECLARE  FOR 
     OPEN  [USING :bnd-var1 [,:bnd-var2,..]]
     FETCH  INTO :select-var1 [, select-var2,...]
     CLOSE 


     Этим методом вначале оператор SQL  подготавливается  (вы-
полняется PREPARE) и затем курсор объединяется с ним (выполня-
ется DECLARE),  выполняется  грамматический  анализ  оператора
SQL, и активные строки идентифицируются. После этих шагов опе-
раторы FETCH начинают захватывать подстроки активного набора.

     По желанию Вы можете использовать в этом методе конструк-
цию USING. Например,

     EXEC SQL PREPARE S FROM :SEL;  (where
         SEL = "SELECT ename
               from emp
               where sal >=
               :a and sal < = :b
               and mgr
               (:c, :d, :e)'

     Заметьте, что имена в конструкции USING являются действи-
тельными именами переменных host-переменных и не требуют соот-
ветствия,  что есть в операторе PREPARE. Фактически, от a до e
не должны быть host-переменными, поскольку они просто являются
носителями места.


                            - 97 -


Пример, показывающий PREPARE, DECLARE, OPEN, FETCH
--------------------------------------------Д


     Следующий пример   запрашивает   конструкцию   WHERE  для
использования в операторе select.


/* Пример #14 */
#include 

/*==========================================================
    Эта программа является примером PRO*C, который запросит
    конструкцию WHERE для использования в операторе select.
    Этот пример использует PREPARE, DECLARE, OPEN & FETCH,
    с этого времени может быть многострочный выбор и требует
    курсор.
==========================================================*/
EXEC SQL BEGIN DECLARE SECTION;
        VARCHAR uid[20];
        VARCHAR pwd[20];
        int deptno;
        char ename[10];
        float sal;
        char select[132];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;

main()
{
   char where[80];
   int scode;
   int i;                                /* счетчик цикла */

   /* log into ORACLE */
   strcpy(uid.arr,"SCOTT");     /*копирует имя пользователя*/
   uid.len=strlen(uid.arr);
   strcpy(pwd.arr,"TIGER");             /* копирует пароль */
   pwd.len=strlen(pwd.arr);

   EXEC SQL WHENEVER SQLERROR GOTO errrpt;
   EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

   printf("Connected to ORACLE user: %s \n",uid.arr);

   strcpy(select,"SELECT ENAME,SAL FROM EMP ");
   printf("Please enter where clause for the following: \n");
   printf("%s",select);
   scode = scanf("%[^\n]",where);
   if (scode == EOF !! scode ==0)
   {
            printf("Invalid entry. \n");
            exit(1);
    }
    strcat(select,where);

    EXEC SQL PREPARE S1 FROM :select;
    EXEC SQL DECLARE C1 CURSOR FOR S1;
    EXEC SQL OPEN C1;
    printf("Employee  \tSALARY   \n");


                            - 98 -

    printf("----------\t---------\n");

    EXEC SQL WHENEVER NOT FOUND GOTO endloop;

    for (i=0; ;i++)
    {
            EXEC SQL FETCH C1 INTO :ename,:sal;
            printf("%10s\t%6.2f\n",ename,sal);
    }

endloop:
   printf("\n\n%d records selected.\n",i);
   EXEC SQL WHENEVER SQLERROR CONTINUE;
   EXEC SQL COMMIT WORK RELEASE;      /* log off database */
   exit(0);

errrpt:
    printf("\n %.70s \n",sqlca.sqlerrm.sqlerrmc);
    EXEC SQL ROLLBACK WORK RELEASE;
    exit(1);
}



МЕТОД 4: ИСПОЛЬЗОВАНИЕ ДЕСКРИПТОРОВ (ОПИСАТЕЛЕЙ)
--------------------------------------------Д

     Динамически определяемые запросы не могут быть  выполнены
с  использованием только операторов PREPARE и EXECUTE.  Запрос
возвратит свой результат в наборе host-переменных,  но  список
SELECT неизвестен до тех пор, пока пользователь не ввел запрос
с терминала.  Поэтому,  число и тип host-переменных  не  могут
быть заданы заранее программистом. Это не является обязательно
недостатком, поскольку будучи способным предвидеть и программ-
но обработать любую ситуацию, программист может написать очень
гибкие и мощные программы на языке host-машины для  доступа  к
базе данных.

     Для написания программы для аккомодации динамических зап-
росов также как и других операторов SQL, Вы используете курсо-
ры вместе с оператором DESCRIBE.

     Оператор DESCRIBE  проверяет список запросов SELECT после
того как он был подготовлен пользователем и определил

     * число столбцов в результате запроса
     * тип данных каждого столбца.

     Затем программа  может  динамически  расположить  область
хранения для содержания этого результата запроса.  Также как и
пре-программированных  запросах,  курсор  объединен  с динами-
ческим запросом,  и строки результата читаются из области хра-
нения, используя команды курсора OPEN, FETCH и CLOSE.

     Для просмотра  команд курсора для нединамических запросов
смотри "Использование курсоров".

     Оператор DESCRIBE  работает  для  любого  подготовленного
оператора SQL,  но не для запросов.  Таким образом,  программы
для динамически  вводимых  операторов  SQL  могут  работать  с
не-запросами также успешно как и с запросами.


                            - 99 -


SQL Descriptor Area (SQLDA)
--------------------------------------------Д

     Область хранения,  расмещенная оператором DESCRIBE, назы-
вается SQL Descriptor Area или SQLDA.  SQLDA никогда не объяв-
ляется  в разделе DECLARE;  она должна быть автоматической или
статической переменной.  Память,  их учитывающая,  размещается
динамически во время выполнения. Для объявления SQLDA Вы може-
те просто включить в начало  программы  следующий  объявляющий
оператор:
               EXEC SQL INCLUDE SQLDA;
     Аналогично SQLCA,  разрешено  кодировать  SQLDA  прямо  в
программе перед использованием оператора SQLDA.  Если  Вы  так
делаете, Вы можете задать любое имя для этой структуры.
     SQLDA чаще  используется в двух случаях в программе:  она
всегда используется в запросах для содержания возвращенной ин-
формации о предметах в списке SELECT, и она может быть исполь-
зована для хранения информации о входных host-переменных (так-
же известных и как связанные переменные).
     Таким образом,  если оператор SQL имеет и заданную и свя-
занную переменные,  тогда требуются два SQLDA.  В  дополнении,
если  программа  имеет  более  чем  один активный оператор SQL
(например, два или более курсора открыты), тогда каждый опера-
тор   SQL   должен  иметь  свой  собственный  подходящий  (или
собственные подходящие) SQLDA.

     Например, следующий оператор DML:

     EXEC SQL DELETE FROM TABA C1 = :v1 AND C2 = :v2;

требует один SQLDA,  содержащий два входа (один для v1 и  один
для  v2).  Следующий  оператор SQL (запрос) требует два SQLDA,
один для заданных переменных (два входа:  d1и d2) и  один  для
связанных переменных (тоже два входа: x1 и y2):

     EXEC SQL SELECT C1, C2
              INTO :d1, :d2
              FROM TABB
              WHERE C3 = :x1 AND C4 = :y2;

     Таким образом,  СУРБД ORACLE возвращает информацию  через
SQLDA, но программа тоже выдает информацию в SQLDA.

     Когда SQLDA используется в обоих случаях, имя SQLDA может
быть выбрано указания ее использования (как в SELECTDA вначале
и BINDDA в последующем использовании), как это показано в сле-
дующем примере:

          EXEC SQL INCLUDE SQLDA;
          SQLDA *bindda, *selectda;
.


                            - 100 -


Значение отдельных элементов SQLDA

     Структура SQLDA в PRO*C показана на рис.10.
Ъ--------------------------------------------------------------ї
і                                                              і
і struct sqlda {                                               і
і  int     N; /* Descriptor size in number of entries     */   і
і  char  **V; /* Ptr to Arr of addresses of main variables*/   і
і  int    *L; /* Ptr to Arr of lengths of buffers         */   і
і  short  *T; /* Ptr to Arr of types of buffers           */   і
і  short  *I; /* Ptr to Arr of addresses of indicator vars*/   і
і  int     F; /* Number of variables found by DESCRIBE    */   і
і  char  **S; /* Ptr to Arr of variable name poiters      */   і
і  short  *M; /* Ptr to Arr of max lengths of var. names  */   і
і  short  *C; /* Ptr to Arr of current lengths of var. names*/ і
і  short **X; /* Ptr to Arr of ind. var. name pointers    */   і
і  short  *Y; /* Ptr to Arr of max lengths of ind. var. names*/і
і  short  *Z; /* Ptr to Arr of cur lengths of ind. var. names*/і
і };                                                           і
і typedef struct sqlda sqlda;                                  і
і                                                              і
А--------------------------------------------------------------Щ
     Рис.10. Структура SQLDA


Новое поведение DESCRIBE
--------------------------------------------Д

     Начиная с версии 1.1 программируемого интерфейса с языка-
ми программирования ORACLE,  поведение DESCRIBE, как использу-
ется для связанных и select-дескрипторов,  более совместимо  с
DB2. Основные изменения состоят в том, что DESCRIBE возвращает
точность и шкалу для NUMBER'ов и указывает,  что  данные  NULL
или NOT NULL.

     Точность и  шкала  возвращаются  с  "длиной" слова SELECT
DESCRIPTOR'a (чье имя системно  независимо).  Шкалой  является
младший байт, выделенный. Точностью является старший байт, не-
выделенный. В C слово "длины" задается в SQLDA.H для того что-
бы быть int.  Однако, оно обрабатывается как 2-байтное для це-
лей выделения точности и шкалы.

     Функция утилиты (доступная в библиотеке времени  выполне-
ния--SQLLIB на VMS) будет выделять точность и шкалу. Однако же
следующий пример показан на C,  концептуальное применение  для
всех языков:


  SQLDA *sdp;                   /* -> SELECT-дескриптор   */
  word  prec;                   /* точность               */
  word  scale;                  /* шкала                  */

  extern VOID sglprc();    /* Выделяет точность и шкалу   */

  sglprc(&sdp->L[i],&prec,&scale);

     Заметьте, что первый аргумент в этой функции является
текущим адресом длины (i-1)-переменной в списке select.

     Заметьте, что все параметры именуются по ссылке.


                            - 101 -

     Индикация NULL/NOT   NULL  возвращается  в  слове  "типа"
списка  select  дескриптора,  который  определен   как   short
(2-байтный).  Если  столбец  позволяет NULL'и,  тогда бит 2ї15
(самый старший бит самого старшего  байта)  является  набором;
иначе если столбец - NOT NULL , бит 2ї15 чистый.

     ORAСLE Programmatic  Interfaces  Runtime Library тоже со-
держит функцию утилиты для NULL:


    SQLDA *sdp;                 /* -> SELECT descriptor    */
    word  dty;                  /* datatype, sans NULL bit */
    word  nullok;               /* 1 NULL; else 0 NOT NULL */

    extern VOID sglnul();
/* Extract Datatype and NULL Indication*/

    sglnul(&sdp->T[i],&dty,&nullok);

    if ( nullok )
      {/* NULL's allowed. */
      }

     Снова заметьте, что параметры пропущены по ссылке.

     Следующее также  допустимо  и  полезно  для  расположения
NULL- бита:


     sqlnul(&sdp->T[i],&sdp->T[i],&nullok);


     Скорее всего, что все существующие програаммы, использую-
щие DESCRIBE, должны быть изменены благодаря возможности того,
что:

     * Любой  тип  данных  ORACLE  может сейчас быть возвращен
       DESCRIBE'ом  (отличие  от  предыдущих  версий,  которые
       только возвращают CHAR и NUMBER).

     * Добавленный (NULL/NOT NULL)-бит в типе данных,  который
       тестирует на определенные  типы  данных  ORACLE,  может
       привести к ошибке благодаря этому новому биту.

     * Столбцы  NUMBER  должны  быть преобразованы в некоторый
       тип данных (СНФК и VARCHAR являются  самыми  безопасны-
       ми). Это благодаря тому факту, что внутреннее представ-
       лением для NUMBER является тип данных, которым не может
       манипулировать пользователь.

     * Если  Вы преобразовываете столбцы в CHAR,  то Вы можете
       вывести их на экран, изменение в том случае, когда сло-
       во длины возвращается для NUMBER'ов,  означает,  что Вы
       ДОЛЖНЫ следить за байтами точности и шкалы, чтобы знать
       сколько пространства распределено. Алгоритм следующий:
.


                            - 102 -

len=prec;
if ( prec == 0 )
   {/* Have NUMBER (i.e., no precision/scale). Use default. */
   len = 40;  /* 40 is the maximum value supported. */
   }
else if ( scale < 0 )
  {/* Have -scale. Need to pad w/ trailing zeros. */
  len = len + (-scale);
  }
len = len + 2;  /* +2 для возможного знака и десятичной точки */

     * Если Вы преобразуете столбцы DATE в CHAR,  то Вы можете
       вывести их на дисплей,  Вы должны разместить 9 символов
       при по умолчании формате DATE для DD-MON-YY.
     * Для столбцов LONG или LONG ROW,  так возвращаемая длина
       0,  Вы должны либо расположить  максимум  либо  выбрать
       максимум.  В  дополнении,  Вы  должны  преобразовать  в
       VARCHAR для дачи длины при захвате.  Заметьте,  что это
       не  работает через SQL*Net для LONG RAW на гетерогенных
       машинах,  что выполняют преобразования набора  символов
       (т.е., ASCII в/из EBCDIC). Текущих cредств решения этой
       проблемы нет.

     Следующая таблица показывает типы, что могут быть возвра-
щены (SQLTYPE), их двоичные/DESCRIBE-длину (DSLEN) и их экран-
ную/преоразования-в-CHAR длину (DSLEN).
Ъ--------------------------------------------------------------ї
і                                                              і
і         COLTYPE     SQLTYPE     DSCLEN      DSLEN            і
і         ________    ________    _______    __________        і
і                                                              і
і         CHAR             1           A            A          і
і         DATE            12           7            9          і
і         DATE (d)        13           7            9          і
і         LONG             8           0            B          і
і         LONG RAW        24           0            B          і
і         NUMBER           2           C            C          і
і         RAW             23           A            A          і
і         ROWID           11          13           18          і
і                                                              і
і  Замечания:                                                  і
і                                                              і
і  A. DSLEN и DSPLEN равны SYSCOLUMNS.WIDTH.                   і
і                                                              і
і  B. DSLEN для всех столбцов LONG является переменной,        і
і  поскольку захваченный LONG COL имеет свою собственную       і
і  длину (т.е., одну длину на строку). Максимальная длина      і
і  столбца LONG (long col) зависит от операционной системы     і
і  (64K на VMS). Смотри также замечание "A".                   і
і                                                              і
і  C. Смотри замечание выше, касавшееся точности и шкалы;      і
і  и требованиетого, что NUMBER должен быть преобразован в     і
і  тип данных пользователя.                                    і
і                                                              і
і  D. Вследствие ошибки, DESCRIBE может вернуть SQLTYPE=13     і
і  (внутреннее данное). Оно должно быть преобразовано во что-  і
і  -нибудь значимое (обычно DATE или CHAR). Эту ошибку можно   і
і  увидеть при выполнении DESCRIBE над выражением DATE, таким  і
і  как:  TO_DATE('1-Mar-86') - 1.                              і
і                                                              і
А--------------------------------------------------------------Щ


                            - 103 -

Замечание: Вы должны очистить бит NULL/NOT NULL в типе  данных
перед использованием типа данных в подпоследовательности OPEN,
FETCH итд.  Вы не должны устанавливать бит NULL/NOT  NULL  при
любых обстоятельствах; это привело бы к ошибке.


Выполнение Runtime-запроса
--------------------------------------------Д

     Шаги выполнения runtime-запроса суммированы на рис. 11.
Ъ--------------------------------------------------------------ї
і                                                              і
і  1. Объявляется структура SQLDA.                             і
і  2. Подготавливается оператор SQL, вводимый пользователем.   і
і  3. Объявляется курсор для имени оператора.                  і
і  4. Размещается содержимое SQLDA.                            і
і  5. Перерасполагается память под SQLDA.                      і
і  6. Описываются связанные переменные в (INTO) связанной SQLDAі
і  7. Открывается курсор.                                      і
і  8. Описывается список SELECT в (INTO) select-SQLDA.         і
і  9. Fetch до конца результата. 10. Закрывается курсор.       і
і                                                              і
А--------------------------------------------------------------Щ
Рис.11. Шаги выполнения Runtime- (динамических) запросов.

     В следующих  разделах  описываются  распределение и пере-
распределение дескрипторов,  и инициализация  и  использование
полей дескрипторов.
     Шаги в написании программы на PRO*C для ответа  на  любой
оператор SQL описаны ниже.  Также Приложение E содержит хорошо
закомментированную программу  PRO*C  для  приема  динамических
операторов SQL. Она иллюстрирует концепции, которые дискутиру-
ются в следующих разделах и могут быть использованы для ссылки
в то время как пишутся программы PRO*C.

Подготовка оператора SQL
     PREPARE делает две вещи:  он проводит грамматический ана-
лиз  оператора  SQL и связывает имя с оператором (имя-операто-
ра).  Заметьте, что точно также как статические запросы, возв-
ращающие   более  одной  строки,  SELECT  может  не  содержать
конструкции INTO.
     Оператор SQL считывается в host-переменную; эта host- пе-
ременная объявляется в разделе DECLARE.  Оператор PREPARE свя-
зывает  эту  переменную  с имянем-оператора;  имя-оператора не
объявляется.

Объявляют курсор для оператора
     Когда объявляется курсор для статических запросов SQL, то
синтаксис следующий:

     EXEC SQL DECLARE cursorname CURSOR FOR query;

     Когда объявляются для динамических запросов, имя-операто-
ра заменяется для статического запроса.

EXEC SQL DECLARE имякурсора CURSOR FOR имяоператора;

где имя-оператора является единственно используемым в операто-
ре PREPARE.


                            - 104 -

Размещение дескриптора
     Для размещения дескриптора, используйте программу sqald:

     sqlda_name = sqlald (a, b, c)

     где:
     a     число переменных для описания
     b     размер стрингов для содержания главных  имен  пере-
           менных (максимальная длина имен host-переменных)
     c     размер стрингов для содержания имен переменной  ин-
           дикатора  (максимальная длина индикатора имен пере-
           менных).

     Программа sqlald  располагает структуру дескриптора в до-
полнении к каждому массиву,  завершаемому полями: V, L, T и I.
Если b отличен от нуля,  массивы, завершаемые полями S, M и C,
размещаются вместе с  пространством  для  главных  переменных.
Если c отличен от нуля,  то массивы, завершаемые полями X, Y и
Z размещаются вместе с пространством для переменных  индикато-
ра. Если b и c нули, то никакого просранства для S, M, C и/или
X, Y или Z не выделяется.
     Если sqlald выполняется,  она возвращает указатель (пойн-
тер) в эту структуру.  Если sqlald выполняется с  ошибкой,  то
она  возвращает  (struct  sqlda  *) 0.  Если sqlda.f меньше 0,
DESCRIBE находит больше элементов, чем a(above) допускала. Вы-
зовите  sqlda  с адресом дескриптора и перевызови sqlda c кор-
ректными параметрами.

Перемещение дескриптора
     Для перемещения дескриптора используйте программу sqlclu,
передающую указатель (пойнтер) дескриптору для размещения:

     sqlclu(sqlda_name);

     Дескриптор должен быть размещен с использованием  sqlald;
если он не был размещен с использованием sqlald, то результаты
будут непредсказуемы.

Описание связанного дескриптора
     Входной или  связанный дескриптор используется для хране-
ния входных переменных, используемых при оценке оператора SQL.

EXEC SQL DESCRIBE BIND FOR statement-name INTO sqlda_name;

Например, если введенный оператор был:

     INSERT INTO EMP (EMPNO, ENAME) VALUES (:empno, :ename);

то те значения,  что пользователь  также  ввел  для  :empno  и
:ename хранятся в связанном дескрипторе и используются в OPEN.

     DESCRIBE BIND должен находится после PREPARE и перед OPEN.

Открытие курсора

     Оператор OPEN (открыть) курсор,  используемый для динами-
ческих запросов,  похож на тот,  что используется  для  стати-
ческих запросов:

     EXEC SQL OPEN cursorname;


                            - 105 -

     Для динамических  запросов (или любых динамических опера-
торов SQL) курсор связан со связанным дескриптором:

     EXEC SQL OPEN cursorname USING DESCRIPTOR sqlda_name;

     Таким образом,  значения, вводимые пользователем и храни-
мые связанным дескриптором используются как связанные перемен-
ные для проверки запроса и идентификации  его  активного  мно-
жества. (Запомните, что текущий запрос или оператор SQL связан
с курсором в операторе DECLARE CURSOR.)  В  том  случае,  если
оператор  SQL запросом не является,  то мы завершаем.  Однако,
для запросов SQL (операторов SELECT) мы  должны  продолжить  с
захватов для текущего восстановления строк.

Описание дескриптора Select

     Если динамический  оператор SQL является запросом,  тогда
оператор DESCRIBE необходим для связывания элементов в  списке
SELECT с выходным дескриптором:

     EXEC SQL DESCRIBE SELECT LIST FOR statementname
     INTO outputdescriptor;

     DESCRIBE SELECT должен находится после PREPARE,  DESCRIBE
BIND и OPEN и перед FETCH;

Захват строк из активного набора

     Оператор FETCH  возвращает  отдельные строки из активного
набора. Тогда как оператор FETCH для статических запросов сле-
дующий:

     EXEC SQL FETCH cursorname INTO outputhostvariables;

оператор FETCH для динамических запросов следующий:

EXEC SQL FETCH cursor_name USING DESCRIPTOR outputdescriptorname;

     Единственное различие состоит в том, что строки возвраща-
ются с использованием заданного выходного дескриптора  (output
descriptor).

Закрытие курсора

     Курсор для  динамических  запросов  закрывается также как
для статических запросов:

     EXEC SQL CLOSE cursorname;

.


                            - 106 -







ГЛАВА 7. ВЫЗОВ PRO*C (КОМАНДА ПРЕКОМПИЛЯТОРА)
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН


     В этой главе описаны команда прекомпилятора и ее опции.



ТРЕБОВАНИЯ, ПРЕДЪЯВЛЯЕМЫЕ К ВЫПОЛНЕНИЮ PRO*C
--------------------------------------------Д

     Основное требование,  предъявляемое  к  выполнению PRO*C,
состоит в том,  что Вы должны прекомпилировать  входной  файл.
Единственным  требуемым  аргументом  является имя этого файла,
предполагающее,  что Вы должны использовать стандартные согла-
шения по заданию имени файла на host-языке. Если Вы используе-
те различные расширения или типы файлов, тогда Вы должны также
задать host-язык.



УСТАНОВКА ДИРЕКТОРИИ ИЛИ ПУТИ
--------------------------------------------Д


     Если Ваша операционная система использует директории или
пути, удостоверьтесь в том,  что имя пути/директории,  включая
устройство, годно. PRO*C создает во время выполнения временный
файл и абортирует его,  если не может открыть этот  файл  (как
было  бы  в том случае,  если есть несоответствие в имени пути
между устройством и директорией).
     Более того,  если  директория,  где был записан временный
файл,  близка к заполнению, PRO*C может наталкиваться на проб-
лемы  записи всего файла.  Если кажется,  что в Ваших выходных
файлах утеряны данные, то постарайтесь удалить некоторый файлы
в этой директории и снова прекомпилировать Вашу программу.




ИЗМЕНЕНИЯ В ВЕРСИИ 5.1 PRO*C
--------------------------------------------Д

     Заметьте, что  эти изменения в версиях runtime-библиотеки
требуют того, чтобы Вы прекомпилировали программы, когда пере-
ходите от версии 4 ORACLE к версии 5.0 СУРБД (Система Управле-
ния Реляционными Базами  Данных)  ORACLE.  Вообще,  невозможна
сквозная  прекомпиляция  программы на машине с различным типом
предназначаемой машины;  прежде, программа должна быть преком-
пилирована снова в одной системе и перемещена в другую систему
с тем же аппаратным обеспечением и той же операционной  систе-
мой.
     В дополнении, прекомпиляторы версии 1 слинкованы в версии
5 СУРБД ORACLE иначе,  чем в предыдущих версиях, в которых они
больше не линкуются в ORACLE.  Преимущество состоит в том, что


                            - 107 -

прекомпиляторы могут быть использованы независимо от любой ба-
зы данных ORACLE.  Другим логическим следствием этого является
тот  факт,  что во время выполнения прекомпилятор не выполняет
никакой проверки синтаксиса SQL, и не выполняет их проверки ни
для имен годной таблицы или столбца. Вместо этого, такие ошиб-
ки обнаруживаются при выполнении программы.

КОМАНДНЫЙ СИСТАКСИС
--------------------------------------------Д

     Для того,  чтобы  увидеть  экран с опциями годных команд,
просто введите:

          PCC

     Этот экран,  показывающий команду, систаксис, опции и па-
раметры, принимаемые по умолчанию, суммирует информацию в сле-
дующих разделах. Общим командным систаксисом является:

      PCC INAME = filename {option=value (option=value ...)}

Требуемые аргументы
--------------------------------------------Д

     Требуетсятолько один  аргумент:  INAME=filename (имя фай-
ла).  Если не задаются расширение файла или тип,  тогда должен
использоваться  аргумент:  HOST=language  (host-язык).  Пустые
расширения файлов  должны  быть  заданы  покиданием  сквозного
(trailing) периода.
     Рисунок 12 на странице 113  показывает  для  операционной
системы  тип файла или расширение по умолчанию,  которые PRO*C
ожидает для входных файлов, и возвращает для выходных файлов.

Если Вы не указываете тип или расширение входного файла, тогда
Вы должны использовать: HOST= option (опция).

Ъ--------------------------------------------------------------ї
і                                                              і
і                           INPUT(вход)         OUTPUT(выход)  і
і    Операционная          Тип файла или        Тип файла или  і
і      система               расширение           расширение   і
Г--------------------------------------------------------------ґ
і      VAX/VMS                 .pc                  .c         і
і     IBM/VM/CMS               csql                 c          і
і        UNIX                  .pc                  .c         і
і                                                              і
і Рис.12. Задание файла по умолчанию в PRO*C                   і
А--------------------------------------------------------------Щ


Опции времени выполнения PRO*C
--------------------------------------------Д

     Отдельные опции доступны во время выполнения.  Общий фор-
мат для задания опции следующий:

     OPTION=value

     Некоторые из  следующих опций могут быть заданы из режима
in- line (без  предварительного  редактирония)  перед  вызовом
прекомпилятора. Эти опции следующие:


                            - 108 -

     AREASIZE
     ERRORS
     INCLUDE
     LITDELIM
     MAXLITERAL
     MAXOPENCURSORS
     REBIND
     XREF

     Опция EXEC ORACLE OPTION особенно полезна в  изменяющихся
значениях,  используемых  во  время прекомпиляции -- например,
изменение AREASIZE на основе курсор-за-курсором. Это также по-
могает  облегчить  проблемы в некоторых операционных системах,
которые имеют ограничения на число символов, которые могут по-
являться в командной строке.
     Опция, вводимая в режиме inline,  отвергнет ту  же  самую
опцию, введенную из командной строки. Вы можете также располо-
жить EXEC ORACLE OPTION в отдельном файле и EXEC  SQL  INCLUDE
включит ее в соттветствующем месте в программе.


AREASIZE
          Этот параметр   задает  контекстуальный  размер  для
курсоров,  открытых программой;  размер,  задаваемый AREASIZE,
отвергнет  контекстуальный размер,  заданный в файле INIT.ORA.
Если опция задается в командной строке,  она используется  как
значение  по  умолчанию  для  всех  курсоров  в этой программе
PRO*C.  Однако,  AREASIZE может быть задана в программе  PRO*C
множество  раз  для  изменений  размера следующего курсора или
множества курсоров.
     Areasize (размер области) задается в килобайтах; по умол-
чанию 16.  Параметр размера области  имеет  в  текущий  момент
только минимальный размер; если курсор требует большего прост-
ранства,  чем указано в этом параметре, PRO*C получает большее
пространство,  больше  чем  задано  параметром  CONTEXT_INCR в
INIT.ORA.

ASACC
          Эта опция  задает  будет или нет листинг-файл следо-
вать за соглашением об управлении каретки ASA, используя стол-
бец 1 каждой строки для управления кареткой. По умолчанию при-
нимается значение "no"; опциями являются (yes, no).

BEGLABEL
          Для C неприменима.

ENDLABEL
          Для C неприменима.

ERRORS
          Эта опция  задает,  куда должны быть посланы ошибки.
По умолчанию  принимается  значение  "yes";  опциями  являются
(yes,  no). Если "yes", то ошибки посылаются и на терминал и в
файл-список. Если "no", ошибки посылаются сразу в файл-список.

FORMAT
          Для C неприменима.

Опции HOLD_CURSOR    и    RELEASE_CURSOR   Две   новые   опции
(HOLD_CURSOR и RELEASE_CURSOR)  могут  быть  использованы  для
"настройки" прикладной программы. Эти опции позволяют програм-


                            - 109 -

мистам контролировать,  как данный оператор SQL обрабатывается
в  кэшпамяти курсора.  Обе опции могут быть использованы в ко-
мандной строке или EXEC ORACLE OPTION.

Ъ--------------------------------------------------------------ї
і                                                              і
і                   HOLD_CURSOR=YESіNO                         і
і                                                              і
і                   RELEASE_CURSOR=YESіNO                      і
і                                                              і
А--------------------------------------------------------------Щ

HOLD_CURSOR=NO Это значение по умолчанию и тот способ, которым
работают  версии  прекомпиляторов,  предшествующих версии 1.1.
После оператора SQL,  который не (NOT)  использует  выполнения
объявленных  (DECLAREd)  курсоров (например,  INSERT,  DELETE,
UPDATE),  элемент кэш-памяти курсора для этого  оператора  SQL
маркируется  как  "используемый снова".  Это значит,  что этот
элемент кэш-памяти курсора оператора SQL может быть  переопре-
делен для использования другим оператором SQL.

HOLD_CURSOR=YES Если значение этого параметра изменено на YES,
то прекомпилятор не  переопределит  элемент  кэш-памяти  этого
оператора  SQL.  Это  применяется для операторов SQL,  которые
используются неоднократно,  и таким образом Вы желаете  сохра-
нить их активными, поскольку Вы избегаете повторения граммати-
ческого  анализа,  который  был  бы  необходим,  если  элемент
кэш-памяти курсора оператора SQL переопределен.

RELEASE_CURSOR=NO Это значение по умолчанию, и тот способ, ко-
торым работают предыдущие версии прекомпилятора.  После опера-
тора  SQL,  который не (NOT) использует выполнения объявленных
(DECLAREd) курсоров (например,  INSERT,  DELETE, UPDATE), эле-
мент  кэш-памяти  курсора  для этого оператора SQL маркируется
как "используемый снова" -- однако, элемент кэш-памяти курсора
не  освобождается -- он осбождается только в том случае,  если
другой оператор SQL заставляет перезадать этот элемет  кэш-па-
мяти.

RELEASE_CURSOR=YES Если  устанавливается значение YES,  то PCC
всегда освобождает элемент кэш-памяти  курсора  для  оператора
SQL после выполнения. Это означает, что каждое выполнение опе-
ратора SQL приведет к выполнению снова граммтического анализа,
итд.  Это применимо для сообщения PCC того,  что этот оператор
SQL выполняется не слишком часто,  и, следовательно, Вы не хо-
тите, чтобы он держал ресурсы базы данных/курсора.

     В следующем  примере  элемент  кэш-памяти не хранится для
оператора SQL:

         EXEC ORACLE OPTION (RELEASE_CURSOR=YES);
         EXEC SQL SELECT DNAME
                  INTO   :NAME
                  FROM   DEPT
                  WHERE  DEPTNO = :NR;
         EXEC ORACLE OPTION (RELEASE_CURSOR=NO);

     Каждое выполнение этого оператора преведет к новому грам-
матическому анализу итд.  Заметьте, что значение по умолчанию,
RELEASE_CURSOR=0,  будет  сброшено после оператора SQL.  Тогда
как в следующем примере:


                            - 110 -


 EXEC ORACLE OPTION (HOLD_CURSOR=YES);
 EXEC SQL INSERT INTO EMP (ENAME,EMPNO,SAL,DEPTNO)
          VALUES (:ENAME-VAR,:EMPNO-VAR,:SAL-VAR,:DEPTNO-VAR);
 EXECORACLE OPTION (HOLD_CURSOR=NO);

оператор SQL  сохраняет свой элемент кэш-памяти курсора прове-
дет грамматический анализ только один раз, независимо от того,
что произойдет в программе.

     Обычно, использовали бы RELEASE_CURSOR=YES для последова-
тельно выполняемых операторов SQL. Эти опции могут значительно
влиять   на  выполнение  программы,  в  зависимости  от  того,
насколько   успешно   Вы   выбираете    разумную    комбинацию
HOLD_CURSOR, RELEASE_CURSOR и MAXOPENCURSORS.

HOST
     Эта опция задает host-язык входной программы. Опциями яв-
ляются  (c/cobol/fortran/pli).  Этот  параметр требуется в том
случае,  если в командной строке не вводится никакого расшире-
ния или типа файла;  если стандартное расширение или тип файла
вводятся как часть имени файла, то этот параметр является нео-
бязательным. Значение по умолчанию не определено.

INCLUDE
     Эта опция задает имя пути  для  include-файлов  EXEC  SQL
(применимы только для операционных систем, использующих пути).
Например, следующее могло бы быть введено для системы xxx:

     PCC INAME=abc INCLUDE= xxx/s/b/c

     Значение по умолчанию для INCLUDE неопределено.

     Вы можете задать INCLUDE=dira INCLUDE=dirb,  итд. Это бу-
дет искать в Вашей локальной директории, затем в dira и ,нако-
нец, в dirb.


IRECLEN
     Эта опция задает длину записи input-файла.  По  умолчанию
80;  максимумом  является  значение  132.  IRECLEN должна быть
меньше или равна ORECLEN.

LITDELIM
     Неприменима для C.

     Эта опция  задает  ограничитель  для  нецифровых символов
COBOL'a.  Опциями  являются  (apost,  quote);   по   умолчанию
"quote".

LNAME
     Эта опция используется для задания имени  файла  выходных
листинг-файлов, отличных от от принимаемых по умолчанию, кото-
рые будут созданы (INAME.LIS или INAME LIST). Листинг-файл за-
писывается в текущую директорию или на диск A.  Например,  для
того чтобы задать выходной файл, Вы можете ввести:

     PCC INAME=BANJO.PC LNAME=VIOLIN.LIS

LRECLEN
     Эта опция задает длину записи листинг-файла. По умолчанию
132, корректным является ввод _to_.


                            - 111 -


LTYPE
     Эта опция  задает  тип листинга.  Опциями являются (long,
short,  non);  по умолчанию "long".  Если  используется  опция
"long",   входные  строки  появляются  в  листинг-файле;  если
используеся опция "short", то они не появляются. Если Вы зада-
ете "none", листингфал не создается.

MAXLITERAL
     Эта опция используется  для  приспособления  определенных
ограничений компилятора к максимальным длинам цепочки символов
(стрингам).  Если это  необходимово  время  прекомпиляции,  то
PRO*C разделит стринги,  превышающие эти значения,  на стринги
этой длины,  и восстановит эти  стринги  после  прекомпиляции.
Значение по умолчанию зависит от языка (1000 для C).

MAXOPENCURSORS
     Эта опция задает количество одновременно открытых  курсо-
ров ORACLE'a или операторов SQL, которые PRO*C пытается сохра-
нить кэшированными. Обычно, прежде чем открыть курсор ORACLE'a
для  каждого курсора PRO*C,  PRO*C пытается использовать снова
другие курсоры ORACLE'a в той  же  самой  ORACLE  Cursor  Data
Area.  PRO*C будет использовать в текущий момент, однако, мно-
гие курсоры, которые необходимы, даже если это количество пре-
высит  MAXOPENCUR-  SORS  (допущением временных дополнительных
курсоров, если это необходимо). По умолчанию 10, что прекрасно
для большинства программ, которые используют относительно мало
открытых курсоров.

     Максимальное значение MAXOPENCURSORS завит от  операцион-
ной  системы  (и  предел  установлен в файле INIT.ORA).  СУРБД
ORACLE требует  максимально  5  курсоров  ORACLE'a.  Используя
MAXOPENCUR-  SORS,  Вы  можете  обойти этот параметр в сторону
меньшего значения,  но у Вы допустите  ошибку,  если  измените
MAXOPENCURSORS на большее значение.

     Если Ваша  программа использует многие операторы SQL,  то
Вы можете желать увеличить MAXOPENCURSORS так,  что максималь-
ное  число  открытых  курсоров  ORACLE'a будет соответствовать
максимальному числу  курсоров  PRO*C,  необходимых  программе.
Установка от 45 до 50 не является необычной, но запомните, что
каждый курсор требует дополнительного контекстуального  прост-
ранства при выполнении задачи пользователя.

ONAME
     Эта опция задает имя выходного файла.  По  умолчанию  это
INAME.C (или INAME C под VM/CMS). Выходной файл записывается в
текущую директорию или на диск А.

ORACA
     Эта опция  задает,  может или нет эта программа использо-
вать ORACLE communications Area (область связей ORACLE'a). Эта
опция может быть "yes" и "no"; "no" по умолчанию. Так Вы долж-
ны включить (INCLUDE) ORACA, используя оператор --

     EXEC SQL INCLUDE ORACA

ORECLEN
     Эта опция задает длину записи выходного файла. По умолча-
нию 80;  максимально 132. IRECLEN должен быть равен или меньше
чем ORECLEN.


                            - 112 -


PAGELEN
     Эта опция задает количество строк на физической странице.
По умолчанию 66.

REBIND
     Эта опция управляет способом обработки PRO*C (операторов)
Bind и Define.  Опции являются "yes" или "no".  YES направляет
прекомпилятор  на  генерацию  кода,  который производит rebind
всех переменных INTO и USING при каждом  выполнении  оператора
SQL.  "YES" по умолчанию. "NO" направляет прекомпилятор на ге-
нерацию кода,  который связывается только в (INTO) и с исполь-
зованием (USING) переменных INTO/USIG один раз за один грамма-
тический  анализ  (например,  один  раз  за  открытый   курсор
ORACLE'a). Обычно, это значит один раз на программу.
     Хотя в ORACLE V4 не было эквивалентного  параметра,  пре-
компиляторы использовали для генерации кодато, что был эквива-
лент к REBIND=0.  Проблема же состояла в том,  что  переменные
INTO/USING, которые передавались как параметры в подпрограмму,
которая содержала оператор SQL, который ссылался на эти некор-
ректно работающие переменные INTO/USING;  поскольку переменные
INTO/USING были объявлены только однажды,  только первый набор
параметров был объявлен в операторе SQL.
     По умолчанию, REBIND=YES, должен работать во всех случаях
(в подпрограмме или нет).  Однако, выполнение BIND cнова может
быть близким к оптимальному, эффективному выполнению и изжерж-
кам, и, таким образом, пользователи, которым не требуется общ-
ность выполнения BIND снова должны выбрать REBIND=0.

SELECT_ERROR
     Эта опция  контролирует сгенерирует ли прекомпилятор осо-
бый вызов по выборке для однострочных запросов,  чтобы  прове-
рить,  что  более чем одна строка могла быть выбрана.  Опциями
являются "yes" (по умолчанию) и "no".  Это изменение было сде-
лано  для  совместимости  с  базой данных IBM DB2,  вследствие
использования SELECT ... INTO. Возьмем оператор:

     EXEC SQL SELECT ENAME
              INTO  :ename
              FROM EMP

     Если запрос выдает  больше  того  строк,  что  годится  в
ename, SQLCODE будет назначено в OER 2112:

     PCC: SELECT ... INTO returns too many rows
                          возвращает слишком много строк

     Если ename скалярного (scalar) типа,  то SQLCODE является
множеством из более чем одной строки, удовлетворяющей запросу.
Если ename - массив (array),  то SQLCODE является  множеством,
если результат переполняет массив.
     Для выполнения этой проверки прекомпилятор должен
сгенерировать дополнительный fetch (захват), таким образом, кое-
что стоящий в выполнении. Опция командной строки позволяет
проверку:

     SELECT_ERROR= [ YES і NO ]

где:
     YES допускает проверку и ошибки вызовут генерацию сообще-
ний об ошибках. По умолчанию "yes".


                            - 113 -

     NO указывает на то, что прекомпилятор не должен генериро-
вать ошибки,  если SELECT ...  INTO возвращает  слишком  много
строк.  Такое  поведение  совместимо с ранними версиями Интер-

фейсов ORACLE'a с языками  программирования  (ORACLE  Program-
matic Interfaces).

USERID

     Эта опция задает имя пользователя ORACLE'a и пароль. Зна-
чение по  умолчанию  не  определено.  Не  задавайте,  если  не
используете  возможность автоматического logon (в именах поль-
зователей ORACLE'a ставится префикс OP$).  Несмотря на то, что
эта опция допускается в PRO*C,  она не является корректной ко-
мандой в версии 5.1.

XREF

     Эта опция задает,  должен ли раздел свозных ссылок  вклю-
чаться  в listing-файл.  По умолчанию "yes";  опциями являются
(yes,no). Сквозные ссылки включаются для host-переменных, имен
курсоров и имен операторов.



ПРИМЕР ПРОГРАММЫ, ИСПОЛЬЗУЮЩЕЙ REBIND
--------------------------------------------Д

/* Пример #16 */
#include 
/*===========================================================
       Это пример программы PRO*C, которая показывает
       использование опции REBIND.
=============================================================

EXEC SQL BEGIN DECLARE SECTION;
        VARCHAR uid[20];
        VARCHAR pwd[20];
        int empno;
        int deptno;
        char ename[15];
        float sal;
EXEC SQL END DECLARE SECTION;

EXEC SQL INCLUDE SQLCA;


main()
{

    int answer;
    char ans;

    /* log into ORACLE */
    strcpy(uid.arr,"SCOTT");    /*копирует имя пользователя*/
    uid.len=strlen(uid.arr);
    strcpy(pwd.arr,''TIGER'');          /* копирует пароль */
    pwd.len=strlen(pwd.arr);

    EXEC SQL WHENEVER SQLERROR GOTO errrpt;


                            - 114 -
    EXEC SQL CONNECT ,uid IDENTIEIED BY ,pwd;

    printf("Connected to ORACLE as user: %s \n",u.ld.arr);

    printf("Do you want to guery by employee number ?  ");
    answer = getchar();
    ans = answer;         /* конвертирует обратно в символ */

    if ((ans ]= 'y') && (ans ]= 'Y'))
    {
    EXEC SQL WHENEVER NOT EOUND GOTO endloop;
    EXEC ORACLE OPTION (REBIND=NO);

    EXEC SQL DECLARE C1 CURSOR FOR
             SELECT ENAME,SAL,DEPTNO EROM EMP;
    EXEC SQL OPEN C1;
    printf("\n\nName           Dept  Salary\n");
    printf("------------*--  ----  ------\n\n");

    while(1)             /* do this for a long time */
    {
            EXEC SQL EETCH CI INTO :ename,:sal,:deptno;
            printf("%.1Ss  %4d %6.2f\n",ename,deptno,sal);
    }
    }
   else
   {
    EXEC SQL WHENEVER NOT FOUND CONTINUE;
    for ( ; ; )
    {
    printf("Enter employee number to gumery on (0 to end):  ");
    sret = scanf("%d",&empno);
    if (sret == EOF !! sret == 0 !! empno == 0)
            break;
    EXEC ORACLE OPTION (REBIND = YES);
    EXEC SQL SELECT ENAME,SAL,DEPTNO
             INTO :ename,:sal,deptno
             FROM EMP
             WHERE EMPNO = :empno;
    printf("Employee: %.1Ss  Department: %4d  Salary:  %6.2f\n",
             ename,deptno,sal);
    }
   }

endloop:
    printf("\n\nProgram completed.\n").
    EXEC SQL WHENEVER SQLERROR CONTINUE;
    EXEC SQL COMMIT WORK RELEASE;      /* log off database */
    exit(0);

errrpt:
    printf("\n %.70s \n",sqlca.sqlerrm.sqlerrmc);
    EXEC SQL ROLLBACK WORK RELEASE;    /* log off database */
    exit(1);
}


                            - 115 -

КОМПИЛЯЦИЯ И ЛИНКОВАНИЕ
--------------------------------------------Д
     За инструкциями по компиляции и редактированию связей об-
ратитесь   к   "Руководству  по  инсталляции  и  пользователя"
(Installation and User's Guide) для Вашей операционной  систе-
мы.




УСЛОВНАЯ ПРЕКОМПИЛЯЦИЯ
--------------------------------------------Д

     Условная прекомпиляция заключается во включении или  иск-
лючении частей кода,  базирующихся на существовании определен-
ных условий (таких как,  включение раздела кода в случае  пре-
компиляции  под CMS или включение другого кода в при прекомпи-
ляции под VMS).  Возможность условной прекомпиляции состоит  в
том, что Вы можете писать программы, которые могут выполняться
в различных средах с использованием  условных  операторов  для
распознавания разделов кода, относящихся к отдельной среде.

     Разделы, являющиеся условными,  обозначаются операторами,
которые определяют среду  и  выполняемые  действия.  Операторы
языков программирования,  так же как и операторы EXEC SQL, мо-
гут быть включены в условные разделы.

     Управление прекомпиляцией поддерживается следующими  опе-
раторами:

ОПЕРАТОР                           ОПРЕДЕЛЕНИЕ
---------------------------------  ------------------------------
EXEC ORACLE DEFINE symbol;         задает символ
EXEC ORACLE IFDEF symbol;          если символ задан
EXEC ORACLE IFNDEF symbol;         если символ не задан
EXEC ORACLE ELSE;                  иначе
EXEC ORACLE ENDIF;                 завершает этот блок управления

     Символы могут быть заданы одним из двух путей:

     * Включением  следующего  оператора  по крайней мере один
       раз в исходную программу:

     EXEC ORACLE DEFINE symbol;

     * Заданием символа в командной строке, как в:

     PCC INAME=xyz ... DEFINE=symbol

     Различные символы в настоящее время  пре-определены.  Они
зависят от порта и задаются в то время,  когда cтроятся Интер-
фейсы с языками программировая ORACLE'a в заданной системе.


          Операционная система          Аппаратное обеспечение
          -------------------------     ------------------------
          CMS                           IBM
          MVS                           DEC
          MSDOS
          UNIX
          VMS

     Следующее является примером того, как управлять прекомпи-
ляцией:


                            - 116 -

     EXEC ORACLE IFDEF testcase;
          EXEC SQL SELECT COUNT(*) INTO counter FROM EMP;
     EXEC ORACLE ENDIF;

     В приведенном выше примере, оператор select будет преком-
пилирован только в том случае,  когда задан символ "testcase",
либо  в программе PRO*C или в командной строке.  Прекомпилятор
раскомментирует код C,  так же как и операторы  EXEC  SQL  или
EXEC ORACLE.

    Блоки условий могут быть расположены как в примере:

     EXEC ORACLE IFDEF xyz;
           EXEC ORACLE IFDEF abc;
           ......
           EXEC ORACLE ENDIF;
           ......
     EXEC ORACLE ENDIF;


     Не существует случаев различий в символах, после того как
PRO*C конвертирует имя символа в верхний регистр.


     Эти операторы  управления  прекомпиляцией  почти функцио-
нально эквивалентны операторам управления препроцессора C.


РАЗДЕЛЬНАЯ ПРЕКОМПИЛЯЦИЯ
--------------------------------------------Д

     Отдельные программы  PRO*C  могут  быть  прекомпилированы
раздельно и слинкованы в одну выполняемую программу. Индивиду-
альные программы не должны быть написаны на том же языке. Кро-
ме  того,  если  программа будет выполняться на различных про-
цессорах,  тогда в то время,  когда она прекомпилировалась,  с
ней  не нужно выполнять PCC снова,  но на самом деле она может
быть поставлена в выполнимой форме (например, файлы .EXE).

     Для того, чтобы прекомпилировать отдельные файлы, следуй-
те следующему порядку:

     1. Прекомпилируйте каждый файл отдельно.

     2. Удостоверьтесь в том, что определения и ссылки к любо-
му задаваемому курсору встречаются только в одном файле. Таким
образом, Вы не можете объявить (DECLARE) курсор в одном файле,
и открыть (OPEN) или захватить (FETCH) из него из другого фай-
ла, который был раздельно прекомпилирован.

     3. SQLCA  и  SQLDA  могут быть переданы как параметры или
могут быть внешними (externals). В последнем случае, Вы должны
включить (INCLUDE) их определения.

     4. Когда   Вы  прекомпилируете  файл,  который  выполняет
CONNECT,  используйте максимальное количество  MAXOPENCURSORS,
что   Вам   потребуется  для  любого  из  этих  файлов.  Опция
MAXOPENCURSORS,  если она используется в любом из других  раз-
дельно   прекомпилированных  модулей,  будет  проигнорирована;
установка для CONNECT  фактически  определяет  текущее  число,
используемое во время выполнения.


                            - 117 -

СОВМЕЩЕНИЕ ПРОГРАММ PRO*C И ORACLE CALL INTERFACE
--------------------------------------------Д

     Операторы PRO*C и OCI (ORACLE Call Interface) могут  быть
записаны в один и тот же программный файл.  Отсутствует разде-
ление на курсоры PRO*C и OCI ORACLE. Если Вы смешиваете опера-
торы PRO*C и OCI в одном и том же файле, то имейте в виду сле-
дующие требования:

     * Программа PRO*C должна выполнить logon (CONNECT)

     EXEC SQL CONNECT :oracleid IDENTIFIED BY :password

     * После подключения программа должна ввести  обращение  к
программе  SQLLIB,  для  того,  чтобы установить Pro*SQL Logon
Data Area, вводя:
     sqllda(lda);
где lda является адресом Logon Data Area, как в стандартных
программах PRO*C.

     При следовании этому соглашению, PRO*C и OCI "знают", что
они "работают вместе".

     Для некоторых операционных систем обращение к SQLLIB  бу-
дет варьироваться. Например, IBM/VM/CMS:

     sq2da(lda)

     Проверьте "Руководство    администратора    баз    данных
ORACLE'a" для интересующей Вас операционной системы.

     Для полного руководства по написанию программ OCI,
обратитесь к Части II этого руководства.


ЧТО ВСТРЕЧАЕТСЯ ВО ВРЕМЯ ПРЕКОМПИЛЯЦИИ
--------------------------------------------Д

     Во время  прекомпиляции  PRO*C  генерирует  в  прикладной
программе последовательность кода С,  что предотвращает выпол-
нение грамматического анализа и BIND'ов снова, если они найде-
ны незначительными.  (Эта  информация  хранится  в  кэш-памяти
курсора.)


Проверка плотности времени выполнения
--------------------------------------------Д

     Библиотека времени выполнения (runtime library) PRO*C вы-
полняет проверку плотности времени выполнения;  таким образом,
Вы  можете  получить  от SQLLIB некоторые сообщения об ошибках
времени выполнения. Ошибки времени выполнения возвращаются че-
рез  стандартную  структуру  SQLCA  (также  как и ошибки СУРБД
ORACLE). Эти ошибки смотри в приложении A.
.


                            - 118 -












ЧАСТЬ II: PRO*C ORACLE CALL INTERFACE



     Как уже было упомянуто в Введении, PRO*C обеспечивает ин-
терфейс с языками программирования, который позволяет ORACLE'у
выполнять прямые обращения из языка высого уровня. Этот интер-
фейс   называется  ORACLE  Call  Interface  (Интерфейс  вызова
ORACLE'a)  или  OCI  и  был  ранее  известен  как  High  Level
Interface (Интерфейс высокого уровня) или HLI. OCI обеспечива-
ет высокую гибкость программисту,  который разрабатывает прик-
ладные  программы,  определяющие  и  манипулирующие  данными в
СУРБД ORACLE.

     Программисты, знакомые с  "Руководством  пользователя  по
PRO*SQL",  должны запомнить, что информация в этой части руко-
водства почти идентична "Руководству пользователя по PRO*SQL".
Однако,  в  отличии  от "Руководства пользователя по PRO*SQL",
примеры, содержащиеся здесь, относятся только к языку C. В до-
полнении, это руководство использует отличную терминологию для
того, чтобы определить программу, использующую OCI. В предыду-
щих версиях "Руководства пользователя по PRO*SQL" на все прог-
раммы на языках высокого уровня, включающие процедуры OCI (или
HLI), ссылались как на программы PRO*SQL. Это руководство ссы-
лается на любую программу высокого уровня,  которая использует
OCI как программу C/OCI.  При ссылке на общие концепции, кото-
рые используются во всех программах, написанных на языке высо-
кого уровня, которые используют вызов OCI, используется термин
программа OCI. Для получения информации по использованию OCI с
другими  языками  высокого  уровня  обращайтесь  к руководству
пользователя по интересующему языку.

     Последующие главы,  представляют полное  описание  ORACLE
Call Interface (OCI). В главе 8 описывается структура програм-
мы OCI.  В главе 9 дается полная информация по каждому  вызову
OCI и приводятся примеры, показывающие как написать каждый вы-
зов OCI на С.  В главе 10 описаны вызовы OCI,  предусмотренные
предыдущими версиями PRO*SQL. В главе 11 представлена информа-
ция по поддерживаемым типам данных  и  конверсиям  этих  типов
данных.  В  приложении этого руководства F представлена закон-
ченная программа на языке С, использующая OCI.

.


                            - 119 -



ГЛАВА 8. ВВЕДЕНИЕ В НАПИСАНИЕ ПРОГРАММ OCI
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН

     В этой главе представлены концепции, используемые при на-
писании программ OCI (ORACLE Call Interface), такие как курсор
области данных,  logon data area, коды возврата, типы парамет-
ров, структуры программы, и дается краткий обзор этих вызовов.

     Язык данных  SQL  является  не-процедурным  языком.  Так,
большинство операторов  выполняются  независимо  от  обработки
предыдущих  операторов.  По сравнению с языками программирова-
ния,  такими как COBOL,  FORTRAN или C.  Эти языки, называемые

процедурными, основываются на таких конструкциях, как "циклы",
"разветвления" и пары "если/то".  Принимая во внимание то, что
язык SQL сам по себе очень мощен,  тем не менее, без процедур-
ных возможностей он имеет некоторые ограничения.

     Имея специально раработанный SQL  для  того,  чтобы  быть
непроцедурным языком, и понимая ограничения такого языка, раз-
работчики SQL также ясно разработали конструкции SQL для того,
что бы он был встроен в процедурных языках программирования. С
помощью этих конструкций, называемых вызовами программы, прог-
раммисты могут писать прикладные программы, которые объединяют
в себе лучшие особенности  SQL  и  лучшие  особенности  языков
программирования.  Эти  прикладные  программы могут быть более
мощными и гибкими,  чем те прикладные программы,  что написаны
либо только на host- или SQL языке.

     При помощи этих вызовов программы, ORACLE может быть свя-
зан с ФОРТРАНом,  КОБОЛом,  C и другими языками программирова-
ния.  Все запросы SQL,  манипуляции данными,  задания данных и
возможности управления данными доступны и из интерактивного  и
интерфейса   с   языками   программирования   (соответственно,
SQL*Plus и ORACLE Call Interface (OCI) ).



ОСНОВНАЯ СТРУКТУРА ПРОГРАММЫ
--------------------------------------------Д

     Программа устанавливает  связь с СУРБД ORACLE выдачей вы-
зова OLON.  Связь осуществляется через Logon Data Area  (LDA),
определенный  в прорамме пользователя.  Программа пользователя
вводит в ORACLE один и только один logon.
     Курсором является  имя  области данных,  используемой для
того,  чтобы распознать и управлять  оператором  SQL.  Область
данных  курсора определяется в программе пользователя.  ORACLE
запрещает программам пользователя иметь много активных  опера-
торов SQL.  Это выполняется отдельной программой вводом многих
OOPEN для того, чтобы создать несколько курсоров.
     OSQL3 связывается с оператором SQL через курсор. Последу-
ющие вызовы для этого  оператора  SQL  ссылаются  на  это  имя
курсора.  Например, вызов OEXEC выполняет оператор SQL. В слу-
чае запроса, вызов OSQL3 задает множество строк для восстанов-
ления  (активное множество) и логически размещает курсор сразу
перед первой строкой.  Затем OFETCH восстанавливает  отдельные
строки из активного множества.


                            - 120 -

     На рисунке 13,  на странице 133, показаны порядок и вызо-
вы,  используемые для того, чтобы программировать запрос SQL в
программе OCI.

Ъ--------------------------------------------------------------Дї
і       OLON            Установка Logon Data Area               і
і        і                                                      і
і        V                                                      і
і       OOPEN           Открытие области данных курсора         і
і        і                                                      і
і        V                                                      і
і       OSQL3           Объединение оператора SQL с курсором    і
і        і              и синтаксический анализ этого оператора і
і        V                                                      і
і       ODEFIN          Задание области буффера программы для   і
і        і              хранения элементов из списка select     і
і        і              (Должен иметься один вызов ODEFIN для   і
і        і               каждого элемента в этом списке.)       і
і        V                                                      і
і       OBNDRV          Пропуск адресов программных переменных, і
і        или            используемых операторе SQL в ORACLE     і
і       OBNDRN          (Один вызов на переменную)              і
і        і                                                      і
і        V                                                      і
і       OEXEC           Выполнение текущего оператора SQL       і
і        і              в заданном курсоре                      і
і        V                                                      і
і ----->OFETCH          Возврат одной строки из таблиц(ы)       і
і і      і              ORACLE'a в область(и) буффера программы,і
і і      і              заданную вызовом ODEFIN                 і
і і нет  V                                                      і
і ------EOF?            Если не все строки извлечены:           і
і        і                   возврат к извлечению               і
і        і                   следующей строки                   і
і        і              Если извлечены все строки:              і
і    да  і                   Если другой оператор SQL:          і
і        і                      к OSQL3                         і
і        і                   Если другая переменная типа BIND:  і
і        і                      изменить программную переменную і
і        V                      к OEXEC                         і
і      OCLOSE           Иначе закрыть курсор                    і
і        і                                                      і
і        V                                                      і
і      OLOGOF           Отсоединение от ORACLE'a                і
А--------------------------------------------------------------ДЩ

     Рисунок 13.
     Логика программы OCI для запроса SQL.


     Каждая программа  OCI защищена от общей потери данных ав-
томатическим механизмом rollback/recovery (удаление  последних
изменений,  внесенных  в базу).  Есть вызовы для подтверждения
транзакций (COMMIT) и для удаления из базы последних изменений
(ROLLBACK) и вызовы для установки механизма восстановления не-
фатальной ошибки.

     Обобщение вызовов,  обсуждаемых   в   этом   руководстве,
представлено на рисунке 14 на странице 135.


                            - 121 -

Ъ--------------------------------------------------------------Дї
і Имя вызова        Цель вызова                                 і
Г--------------------------------------------------------------Дґ
і OLON              Подсоединиться к ORACLE'у.                  і
і                                                               і
і ORLON             Создать конкурирующие подсоединения         і
і                   к ORACLE'у.                                 і
і OOPEN             Создать курсор.                             і
і                                                               і
і OSQL3             Пропустить оператор SQL в ORACLE.           і
і                                                               і
і ODSC              Определить тип, размер и статус столбца     і
і                   в операторе SQL.                            і
і                                                               і
і ONAME             Определить имя столбца в операторе SQL.     і
і                                                               і
і ODEFIN            Идентифицировать расположение и тип области і
і                   в программе для приема данных из ORACLE'a   і
і                   (задать массив).                            і
і OBNDRV            Выделить данные из программы пользователя в і
і                   переменную оператора SQL (связать массив).  і
і                                                               і
і OBNDRN            Выделить данные из программы пользователя в і
і                   переменную оператора SQL (связать массив).  і
і                                                               і
і OOPT              Выбрать опции для многострочного            і
і                   восстановления ошибки.                      і
і                                                               і
і OEXEC             Обработать оператор SQL.                    і
і                                                               і
і OEXN              Разрешить операции, использующие массив     і
і                   переменных типа bind.                       і
і                                                               і
і ORES              Не поддерживается.                          і
і                                                               і
і OFETCH            Восстановить данные в заданные области      і
і                   данных по строке за один раз.               і
і                                                               і
і OFEN              Одним вызовом извлечь несколько строк       і
і                   в массив заданных переменных.               і
і                                                               і
і OBREAK            Завершить текущую функцию ORACLE'a.         і
і                                                               і
і OCAN              Показать, что текущая функция завершена.    і
і                                                               і
А--------------------------------------------------------------ДЩ
.


                            - 122 -


Ъ--------------------------------------------------------------Дї
і Имя вызова        Цель вызова (продолжение)                   і
Г--------------------------------------------------------------Дґ
і OCOM             Подтвердить текущую транзакцию               і
і                  в базу данных.                               і
і                                                               і
і OROL             Восстановить последнее перед транзакцией     і
і                  состояние базы данных.                       і
і                                                               і
і OCON             Включить режим автоматического подтверждения і
і                  транзакций                                   і
і                                                               і
і OCOF             Выключить режим автоматического подтвержденияі
і                  транзакций                                   і
і                                                               і
і OERSMG           Извлечь текст сообщения, соответствующий но- і
і                  ру ошибки ORACLE'a.                          і
і                                                               і
і OCMN             Не поддерживается.                           і
і                                                               і
і OCLOSE           Удалить курсор.                              і
і                                                               і
і OLOGOF           Отсоединиться от ORACLE'a.                   і
А--------------------------------------------------------------ДЩ

     Рисунок 14.
     Сводка вызовов функций.




ОБЛАСТЬ ДАННЫХ КУРСОРА
--------------------------------------------Д

     Курсор является  64-байтной областью данных,  связанной с
активным оператором SQL и заданной в  программе  пользователя.
Курсор  идентифицируется  в  ORACLE'e  (задается имя) в вызове
OOPEN.  Каждый последующий вызов ORACLE'a, ссылающийся на этот
оператор SQL, использует это имя курсора. Облать данных курсо-
ра содержит информацию о статуседля активной операции SQL.
     Программа может иметь многие курсоры. Максимальным числом
курсоров, которые могут быть открыты за один раз, является 150
минус те,  что используются ORACLE'ом (около 5). Однако, теку-
щий максимум в интересующее время зависит от доступной памяти.
     Схема области  данных  курсора  является  машинозависимой
из-за различий в компиляторах C.  Однако,  все поля и значения
приведены для всех машин.  Проверьте "Руководство по инсталля-
ции и пользователя ORACLE'a" для  Вашей  операционной  системы
для того,  чтобы увидеть в точности, как поля называются и как
пронумерованы. Формат области данных курсора для VAX/VMS изоб-
ражен на рисунке 15, на странице 138; он приведенн в виде при-
мера.  Обратитесь к руководству по инсталляции и  пользователя
для Вашей операционной системы для того,  чтобы увидеть точную
схему для Вашей операционной системы.
     Схема, длины  полей  и расположения байтов области данных
курсора являются системно-зависимыми.  Рисунок 19 приведен для
VAX/VMS, VAX/UNIX и IBM.
.


                            - 123 -

     +------------------------------------------+
     і 0                    і 2                 і
     і      КОД ЗАВЕРШЕНИЯ  і    ТИП ФУНКЦИИ    і
     і------------------------------------------і
     і 4                                        і
     і            ЧИСЛО ОБРАБОТАННЫХ СТРОК      і
     і------------------------------------------і
     і 8   УКАЗАТЕЛЬ        і 10  ТИП  і 11     і
     іСИНТАКСИЧЕСКОЙ ОШИБКИ і ФУНКЦИИ  і РЕЗЕРВ і
     і------------------------------------------і
     і 12                   і 14       і 15     і
     і     V4  КОД ОШИБКИ   і  ФЛАГИ1  і ФЛАГИ2 і
     і------------------------------------------і  ---
     і 16                                       і   і
     і               ЧИСЛО КУРСОРОВ             і   і
     і------------------------------------------і   і
     і 20                                       і   і
     і ВНУТРЕННИЙ ИДЕНТИФИКАТОР СТРОКИ (ROWID)  і   і
     і------------------------------------------і   і
     і 24    ВНУТРЕННИЙ ИДЕНТИФИКАТОР СТРОКИ    і   і
     і       (ROWID)    -продолжение-           і область,
     і------------------------------------------і зависящая
     і 28    ВНУТРЕННИЙ ИДЕНТИФИКАТОР СТРОКИ    і от ОС
     і       (ROWID)    -продолжение-           і   і
     і------------------------------------------і   і
     і 32 ВНУТРЕННИЙі 33                        і   і
     і      ROWID   і   OSD КОД ОШИБКИ          і   і
     і------------------------------------------і   і
     і 36             і 37  БАЙТ   і 38         і   і
     і  OSD-ОШИБКА    і  ПРОВЕРКИ  і ORAPARMS...і   і
     і------------------------------------------і   і
     і 40          СИСТЕМНЫЕ ПАРАМЕТРЫ          і   і
     і             ORACLE'a -пролжение-       63і   і
     +------------------------------------------+  ---

     Рисунок 15. Схема области данных курсора

     Код завершения
     Содержит двубайтный двоичный номер, который указывает код
завершения для вызова прекомпилятора.

   ноль                    указывает на успешный результат.
   положительное число     указывает на успешный результат с
                           необычным условием.
   отрицательное число     Указывает на ошибку, всреченную при
                           попытке выполнить заданную операцию.

      Некоторые коды  ошибок оттранслированы для совместимости
ORACLE версия 2. Используйте поле V4 КОД ОШИБКИ, если Вы хоти-
те увидеть неоттранслированные коды.

Ъ--------------------------------------------------------------Дї
і         V2        Объяснение                          V4      і
Г--------------------------------------------------------------Дґ
і         +2        извлечен нулевой столбец             1405   і
і         +3        столбец отсечен при извлечении       1406   і
і         +4        конец выборки                        1403   і
і       -303        переменной нет в списке select       1007   і
і         -9        дублированное значение в индексе        1   і
і       -605        переменная типа bind не существует   1006   і
А--------------------------------------------------------------ДЩ


                            - 124 -

     Другие коды возврата ошибки приведены в  "Руководстве  по
кодам и сообщениям об ошибках ORACLE'a". (Также, заметьте, что
OERSMG ищет код ошибки  версий  2/3;  однако,  отрицание  кода
ошибки версии 4 будет также работать.)

Тип функции    Используется внутри ORACLE'a подлежит изменению
               между версиями.

Ъ--------------------------------------------------------------Дї
і              Значение            Тип                          і
Г--------------------------------------------------------------Дґ
і              1                   CREATE TABLE                 і
і              3                   INSERT                       і
і              4                   SELECT                       і
і              5                   UPDATE                       і
і              7                   DROP VIEW                    і
і              8                   DROP TABLE                   і
і              9                   DELETE                       і
і              10                  DEFINE VIEW                  і
і              11                  EXPAND                       і
і              18                  CREATE CLUSTER               і
і              20                  CREATE INDEX                 і
і              21                  DROP INDEX                   і
і              22                  DROP CLUSTER                 і
і              23                  CREATE SPACE                 і
і              24                  ALTER SPACE                  і
і              25                  DROP SPACE                   і
і              26                  ALTER TABLE                  і
і              27                  EVALUATE                     і
і              28                  GRANT                        і
і              29                  REVOKE                       і
і              30                  CREATE SYNONYM               і
і              31                  DROP SYNONYM                 і
А--------------------------------------------------------------ДЩ

Число обработанных строк  Содержит 4-битное двоичное число, ука-
               вающее число строк, обработанных операцией SQL.
               Это число указывает количество строк, введенных,
               замененных или удаленных оператором, манипули-
               рующим данными или или число строк, извлеченных
               оператором запроса. Это поле допустимо только
               после вызовов OEXEC или OFETCH.

Указатель синтаксической ошибки  Содержит 2-байтное двоичное
               число, указывающее местоположение синтаксической
               ошибки (в символах) в операторе SQL. Это поле
               допустимо только после операции OSQL или OSQL3.

Тип функции  Содержит код, указывающий запрашиваемый вызов OCI.
             Код функции имеется для любого вызова OCI, который
             использует область данных курсора; вызовы, ссылаю-
             щиеся только на logon data area не имеют кода
             функции.
.


                            - 125 -

Ъ--------------------------------------------------------------Дї
і              Код                 Функция                      і
Г--------------------------------------------------------------Дґ
і              02                  OSQL                         і
і              04                  OEXEC                        і
і              06                  OBIND                        і
і              08                  ODFINN                       і
і              10                  ODSRBN                       і
і              12                  OFETCH                       і
і              14                  OOPEN                        і
і              16                  OCLOSE                       і
і              22                  ODSC                         і
і              24                  ONAME                        і
і              26                  OSQL3                        і
і              28                  OBNDRV                       і
і              30                  OBNDRN                       і
і              32                  OOPT                         і
і              50                  OBINDN                       і
А--------------------------------------------------------------ДЩ
V4 Код ошибки  Поле кода завершения транслирует некоторые коды
               ошибок ORACLE'a в номера, используемые в ORACLE
               версия 2. Это поле всегда будет иметь прямые, те-
               кущие, неоттранслированные номера сообщений об
               ошибке, как показано в "Руководстве по кодам и
               сообщениям об ошибках ORACLE'a".

Флаги1         Битовые флаги предупреждений. Может быть выстав-
               лено боле одного.
Ъ--------------------------------------------------------------Дї
і    Значение бита       Смысл                                  і
Г--------------------------------------------------------------Дґ
і              1         Это предупреждение. Он выставляется,   і
і                        когда в Флаги1 выставлен любой другой  і
і                        бит.                                   і
і              2         Выставляется, если любой элемент данныхі
і                        отсекается при OFETCH                  і
і              4         Выставляется, если значения типа NULL  і
і                        были использованы в группирующей       і
і                        функции.                               і
і             16         Выставляется, если синтаксис оператора і
і                        update или delete анализируется без    і
і                        конструкции where.                     і
і             64         Выставляется,если был выполнен ROLLBACKі
і            128         Выставляется, если отсечены            і
і                        противоречивые данные.                 і
А--------------------------------------------------------------ДЩ


Флаги2  Флаги дополнительных предупреждений.

Ъ--------------------------------------------------------------Дї
і    Значение бита       Смысл                                  і
Г--------------------------------------------------------------Дґ
і              1         Не используется.                       і
і              2         Выставляется при фатальной ошибке и    і
і                        при полностью аннулированной           і
і                        транзакции.                            і
і              4         Выставляется, когда были отменены      і
і                        изменения только в одной строке.       і
і              8         Не используется.                       і
А--------------------------------------------------------------ДЩ


                            - 126 -

Номер курсора  Внутренний номер курсора (двоичный целый),
               применяемый ORACLE'ом для того, чтобы
               отследить курсоры, используемые различными
               процессами.

Внутренний идентификатор строки (ROWID) Идентификатор строки во
                внутреннем формате.
Ъ--------------------------------------------------------------Дї
і                                                               і
і    4 байта:       RBA первого блока таблицы (не реализован)   і
і    2 байта:       Номер разделения                            і
і    1 байт:        идентификатор таблицы в кластере            і
і                   (не реализован)                             і
і    4 байта:       логический блок                             і
і    2 байта:       последовательность строк                    і
і                                                               і
А--------------------------------------------------------------ДЩ

     Идентификатор строки  (ROWID)  может быть конвертирован в
     шестнадцатеричный формат и отформатирован для того, чтобы
     создать цепочку символов,  которая идентична ROWID, возв-
     ращаемого при помощи операторов SQL SELECT.  Дополнитель-
     ную информацию об идентификаторах строки (ROWID) смотри в
     "Администраторе баз данных ORACLE".

OSD  Код ошибки Код ошибки,  зависящий от операционной системы,
     и,  cвязанный с ошибкой ORACLE'a.  Например, на VMS, если
     ошибка ORACLE'a 509 (сбой $write в BWR),  то  код  ошибки
     OSD будет иметь текущий код сбоя системы ввода/вывода.

Байт проверки Байт,  используемый для определения того,  явля-
     ется или нет допустимой область данных курсора,  заданная
     вызовом  ORACLE'a.  Его значение выставляется ORACLE'ом и
     никогда не может быть изменено программой пользователя.

.


                            - 127 -


LOGON DATA AREA
--------------------------------------------Д

     Logon Data Area (LDA) является 64-байтной областью,  свя-
занной с каждым активным соединением (logon)  к  ORACLE'у.  Ее
формат идентичен области данных курсора,  исключая то,  что не
все поля используются в LDA.


     +------------------------------------------+
     і 0                    і 2                 і
     і      КОД ЗАВЕРШЕНИЯ  і      РЕЗЕРВ       і
     і------------------------------------------і
     і 4                                        і
     і                   РЕЗЕРВ                 і
     і------------------------------------------і
     і 8                    і 10       і 11     і
     і      РЕЗЕРВ          і  РЕЗЕРВ  і РЕЗЕРВ і
     і----------------------і----------і--------і
     і 12                   і 14       і 15     і
     і     V4  КОД ОШИБКИ   і          і        і
     і------------------------------------------і
     і                      .                   і
     і                      .                   і
     і                      .                   і
     і------------------------------------------і
     і 32             і 33                      і
     і     РЕЗЕРВ     і   OSD КОД ОШИБКИ        і
     і----------------і-------------------------і
     і 36             і 37  БАЙТ   і 38         і
     і  OSD-ОШИБКА    і  ПРОВЕРКИ  і ORAPARMS...і
     і------------------------------------------і
     і 40          СИСТЕМНЫЕ ПАРАМЕТРЫ          і
     і             ORACLE'a -пролжение-       63і
     +------------------------------------------+

     Определения идентичны тем, что даны для области данных
курсора.



ОБЛАСТИ ДАННЫХ ИНТЕРФЕЙСА С ЯЗЫКАМИ ПРОГРАММИРОВАНИЯ
----------------------------------------------

ORACLE позволяет одной программе одновременно иметь  несколько
открытых курсоров.

Чтобы оптимизировать работу программы,  полезно понимать,  как
организована связь между ORACLE и программой пользователя.
.


                            - 128 -

Ниже приведена диаграмма пользовательской программы под назва-
нием UPDT3, с двумя открытыми курсорами.

    ПРОГРАММА ПОЛЬЗОВАТЕЛЯ                    ORACLE
Ъ----------------------------Дї    Ъ--------------------------Дї
і           UPDT3             і    і       ОБЛАСТЬ СВЯЗИ       і
і                             і    і  Ъ--------Дї Ъ--------Дї  і
і       Ъ------------Дї       і    і  і  UPDT3  і інеисполь-і  і
і       і СВЯЗАТЬ LDA і       і    і  і   PGA   і і зуемая  і  і
і       А------------ДЩ       і    і  іЪ--ї Ъ--їі і   PGA   і  і
і                             і    і  ііC1і іC2іі і         і  і
і  Ъ----------ї Ъ----------ї  і    і  іА--Щ А--Щі і         і  і
і  іОТКРЫТЬ C1і іОТКРЫТЬ C2і  і    і  А--------ДЩ А--------ДЩ  і
і  А----------Щ А----------Щ  і    іНННННННННННННННННННННННННННі
і                             і    і                           і
і   SELECT        UPDATE      і    і                           і
і   FROM          SET         і    і        O R A C L E        і
і   WHERE         WHERE       і    і                           і
і                             і    і                           і
А----------------------------ДЩ    А--------------------------ДЩ

Когда программа UPDT3 обращается к функции OLON,  ORACLE выде-
ляет для UPDT3 глобальную область  программы  (Program  Global
Area  -  PGA).  ORACLE  подсоединяет  эту PGA к области данных
подсоединения (Logon Data Area - LDA),  выделенной в программе
UPDT3. ORACLE выделяет одну и только одну PGA для каждого про-
цесса (программы), подсоединенного к ORACLE.

Когда программа UPDT3 вызывает функцию OOPEN,  ORACLE выделяет
для UPDT3 рабочую область SQL (SQL Work Area - SWA) (или "кон-
текстную область").  ORACLE подсоединяет SWA к  курсору  (C1),
определенному в UPDT3.

Когда программа UPDT3 снова обращается к OOPEN, ORACLE выделя-
ет еще одну SWA и подсоединяет  ее  к  другому  курсору  UPDT3
(C2). Для каждого открытого курсора ORACLE выделяет SWA.

По-умолчанию размер каждой SWA параметром context_size в файле
INIT.ORA. Пользователь может задать свой размер, используя па-
раметр areasize при обращении к OOPEN.  SWA должна быть доста-
точно большой,  чтобы содержать скомпилированный оператор  SQL
плюс одну строку из обрабатываемой таблицы или концептуального
разреза данных (обзора (view)).


ОБЩИЕ ПРАВИЛА КОДИРОВАНИЯ

При обращении  к ORACLE можно использовать несколько различных
типов параметров:  адресные параметры передают в ORACLE адреса
параметров.  Некоторые адресные поля всегда указывают на пара-
метры одного и того же типа,  например,  адрес LDA в  функциях
OLON и OOPEN. Другие адресные поля указывают на параметры раз-
ных типов, например адрес буфера в функции ODEFIN.

двоичное целое число (binary integer)
число, длина которого определяется длиной слова в машине.

DEC VAX/VMS                   32 бита
IBM VM/CMS                    32 бита
DEC PDP-11                    16 битов


                            - 129 -

Узнать длину  двоичного целого числа в Вашей машине можно из в
Руководства по Установке  ORACLE  и  Руководства  Пользователя
(ORACLE  Installation and User's Guide) для вашей операционной
системы.

короткое двоичное целое число (short binary integer)
число, длина которого может быть меньше длины машинного слова.

DEC VAX/VMS                   16 битов
IBM VM/CMS                    16 битов
DEC PDP-11                    16 битов

Узнать длину короткого двоичного целого числа в Вашей машине
можно из в Руководства по Установке ORACLE и Руководства Пользо-
вателя (ORACLE Installation and User's Guide) для вашей
операционной системы.

Ниже приведены некоторые общие правила для программ,  работаю-
щих с ORACLE:

Символьные строки могут быть ограничены нулевым символом, т.е.
последний символ в строке имеет код 0. Если строка не заканчи-
вается нулевым символом,  то необходимо указать ее длину в ка-
честве дополнительного параметра  (см.  "параметры  переменной
длины"). В списке параметров могут стоять литералы (символьные
константы), если используемый комилятор это допускает. Обрати-
те внимание, что при вызове функции с литералом в качестве па-
раметра должна порождаться ссылка на этот литерал.  Более под-
робную  информацию можно почерпнуть в Руководстве по Установке
ORACLE и Руководстве  Пользователя  (ORACLE  Installation  and
User's Guide) для вашей машины. Параметры переменной длины пе-
редаются в ORACLE вместе с параметром,  указывающим их длину в
следующей форме:
   адресный параметр, двоичное целое число

Параметры длины - это двоичные целые числа, указывающие размер
(в  байтах)  параметра переменной длины.  Параметр длины можно
опустить,  если параметр переменной длины  ограничен  двоичным
нулем. Если длина указана, то завершающий ноль игнорируется.


Необязательные Параметры
----------------------------------------------

Необязательные параметры допускаются, только если используемый
компилятор позволяет пропускать их.  Если это не  допускается,
то все параметры обязательны.  Если поле длины или другой нео-
бязательный параметр отсутствует в списке параметров, то поль-
зователь  должен  поставить две запятые (,,),  чтобы показать,
что параметр пропущен, если, конечно, компилятор допускает та-
кую запись. Например:

   "параметр1,длина1,параметр2,длина2"

может превратиться в:

   "параметр1,,параметр2,,"

В некоторых   языках   (например,   в   СИ)  нельзя  указывать
отсутствие параметра двумя запятыми подряд. В этом случае мож-
но  передавать  минус единицу (-1),  чтобы указать пропущенный
параметр. Например:


                            - 130 -

   (параметр1,-1,параметр2,-1)

В языках,  не  допускающих  пропусков  параметров,  в  которых
вместо всех параметров передаются ссылки на них, на месте про-
пущенных параметров должна стоять ссылка на двоичную целую пе-
ременную,  значение которой -1. Пропущенные необязательные ад-
ресные параметры (например,  адрес индикаторной  переменной  в
функции ODEFIN) должны обозначаться значением -1.  Если компи-
лятор не допускает непосредственной передачи значений,  то все
адресные  параметры  обязательны.  Если  компилятор  допускает
опускать параметры в конце списка,  то  необязательно  ставить
запятые,  если пропущенные параметры стоят в конце списка. Та-
кие языки как СИ не допускают использование необязательных па-
раметров ни в конце ни в середине списка.


Использование Заменяемых Переменных
----------------------------------------------

При использовании  SQL  в  некотором  языке  программирования,
внутри опереаторов SQL можно использовать заменяемые  перемен-
ные.  Заменяемые переменные (substitution variables) позволяют
программам динамически изменять операторы SQL,  которые  затем
могут быть выполнены с новыми значениями.

Заменяемые переменные SQL идентифицируются двоеточием. Заменя-
емые переменные можно использовать  в  любом  месте  оператора
SQL, где можно использовать константу. Например, следуещее об-
ращение к OSQL (написанное на СИ) использует  одну  заменяемую
переменную (:DEPT), вместо которой может быть подставлен номер
любого отдела (DEPTNO - сокращение от department number -  но-
мер отдела):

   osql3 (CUR1,"SELECT ENAME,SAL FROM EMP WHERE DEPTNO = DEPT");

Затем используются  функции OBNDRV и OBNDRN,  чтобы подставить
фактические значения вместо заменяемых переменных:

   obndrv (CUR1,":DEPT",5,DEPT,2,3,1,short *(-1),char *(1),0,-1);

(где DEPT - переменная,  определенная в программе пользователя
как 2-байтовое число с фиксированной точкой).

Заменяемые переменные  SQL  используются также для подстановки
значений в операторы INSERT и UPDATE. В следующем примере зна-
чения связанные с заменяемыми переменными (:A, :B, :C) помеща-
ются в соответствующие поля (DEPTNO,DNAME и LOC),  а в  EMPCNT
помещается пустое данное (null).

osql3 (CUR2,"INSERT INTO DEPT (DEPTNO,DNAME,LOC,EMPCNT) VALUES
                              (:A,:B,:C,NULL)",-1);

Пустые данные можно помещать в базу,  указывая NULL  в  списке
оператора  INSERT,  или  связывая  с заменяемой переменной SQL
значение,  длина индикаторной переменной (indicator  variable)
для которого равна нулю:

   obndrv (CUR2,":C",2,LOC,14,1,1,0);

См. также описание обращений к функциям OBNDRV и OBNDRN.
Пример определения OSQL3 приведен в главе 9.


                            - 131 -

Использование Индикаторных Переменных
----------------------------------------------

Индикаторные переменные  используются как при связывании так и
при  определении   переменных,   содержащих   значения   (host
variables).

При обращении к функциям OBNDRV и OBNDRN индикаторная перемен-
ная может использоваться для связывания заменяемой  переменной
с пустым данным (если indp указывает на отрицательное число).

Поскольку символьные поля могут дополняться концевыми пробела-
ми, progvarl должна указывать максимальное число символов, ко-
торые  будут  связаны с заменяемой переменной,  с учетом того,
что Pro*C SQL удалит концевые пробелы.

При обращении к ODEFIN индикаторная переменная  может  показы-
вать,  является  ли извлеченное значение поля пустым,  было ли
оно усечено или оставлено без изменений, принимая одно из сле-
дующих значений:

               tsize = 10.

отрицательное     Извлечено пустое данное.

ноль           Длина извлеченного значения не превышала  длины
               выделенного под него программного буфера.

положительное  Извлеченное значение  не поместилось в выделен-
               ный под него буфер. Возвращаемое в индикаторной
               переменной положительное число показывает длину
               излеченного поля до помещения его в буфер (т.е.
               до отсечения).

Замечания об Использовании Оптимизирующих Компиляторов
----------------------------------------------

Во многих компиляторах есть возможность оптимизировать генери-
руемый ими код таким образом,  что адреса переменных программы
не  все  время точно отражают их действительное расположение в
памяти.  Например,  некоторые такие компиляторы  хранят  часто
используемые  переменные  в  регистрах  и  заносят их в память
только когда их надо передать в подпрограмму.

Когда адрес  переменной,  которая  используется  в  дальнейшем
(например,  адреса  буферов  при  работе  с функциями ODEFIN и
OBNDRV/OBNDRN) передается  в  ORACLE  как  параметр,  то  надо
обеспечить,  чтобы  когда  она  будет использоваться функциями
OFETCH и OEXEC,  эта переменная располагалась в том  же  самом
месте памяти.

Самый простой  способ обеспечить соответствие адресов перемен-
ным - отключить оптимизацию при компилировании.


                            - 132 -


ОПИСАНИЯ ОБРАЩЕНИЙ К
ФУНКЦИЯМ OCI
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН

В этой главе описывается обращение к каждой функции интерфейса
ORACLE (ORACLE Call Interface - OCI).  Каждой функции посвящен
раздел,  в котором описан синтаксис обращения к ней, расказано
как ее использовать и что означают ее параметры,  а также при-
ведены примеры обращений из языков ФОРТРАН, КОБОЛ и СИ. Описа-
ния вызовов подпрограмм следуют не по алфавиту,  а примерно  в
том порядке,  в котором они должны появляться в программе.  (В
алфавитном порядке эти функции перечислены в приложении G.)

Слова "функция" и "подпрограмма"  будем  использовать  в  этой
главе как синомы.




ФУНКЦИЯ OLON
----------------------------------------------------------------

Ъ------------------------------------------------------------Дї
і CALL OLON ( lda [,uid, uidlen] [,psw, pswl] [,audit_flag] );і
А------------------------------------------------------------ДЩ

Функция OLON  устанавливает связь между программой пользоваеля
и ORACLE.

Связь осуществляется через специальную область данных связи  -
LDA  (logon  data  area),  выделяемую программой пользователя.
Функция OLON связывает LDA и ORACLE.

Программа может несколько раз подсоединиться к ORACLE,  но од-
новременно  активным может быть только одно обращение к OLON и
одно имя пользователя.  Чтобы переключиться на другого пользо-
вателя,  использующего  ту  же LDA,  надо обратиться к функции
OLOGOF,  а затем вызвать OLON с  другим  именем  пользователя.
Чтобы  переключиться  на  другого пользователя,  использующего
другую LDA,  можно воспользоваться подпрограммой ORLON. Однов-
ременно программа может иметь одну и только одну LDA.

Если после обращения к подпрограмме OLON будет вызвана функция
OLOGOF,  то все неподтвержденные еще транзакции подтверждаются
(т.е.  соответствующие  им  изменения в базе данных становятся
постоянными). Если программе пользователя не удается нормально
отсоединиться,  или  она аварийно завершается,  то все неподт-
вержденные еще транзакции анулируются (т.е.  анулируются соот-
ветствующие им изменения в базе данных).

LDA -  это область данных размером в 64 байта,  определенная в
программе пользователя.  Число в формате short binary  integer
(короткое  двоичное  целое) в начале этой области содержит код
завершения, показывающий чем кончилось обращение к OLON. Нуле-
вой  код завершения означает что подсоединение к ORACLE прошло
нормально.  Коды завершения, соответствующие возникшим ошибкам
перечислены  в  книге  "Сообщения об Ошибках ORACLE и их Коды"
(ORACLE Error Messages and Codes Manual).


                                   - 133 -

lda (адрес)
            - адрес 64-байтовой области связи,  определенной в
              программе пользователя.

uid (адрес) - адрес символьной строки,  содержащей имя пользо-
              вателя  и может быть пароль.  Если пароль содер-
              жится в uid,  то он должен быть отделен от имени
              пользователя символом "/".

uilen (двоичное целое число)
            - длина строки, на которую указывает uid. Если эта
              строка  оканчивается  нулевым символом,  то этот
              параметр можно опустить.

psw (адрес)
            - адрес пароля. Если пароль входит в параметр uid,
              то параметр psw не требуется.

pswl (двоичное целое число)
            - длина пароля.  Если строка, на которую указывает
              psw,  оканчивается нулевым символом, то этот па-
              раметр можно опустить.

audit_flag (двоичное целое число)
            - не поддерживается;  единственное допустимое зна-
              чение - двоичный целый 0 (ноль).

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OLON                      і
Г--------------------------------------------------------------Дґ
і                                                               і
і              olon(lda,uid,-1,(char *)-1,-1,0);                і
А--------------------------------------------------------------ДЩ


ФУНКЦИЯ ORLON
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і CALL ORLON ( lda, hda [,uid, uidlen] [,psw, pswl]             і
і                                               [,audit_flag] );і
А--------------------------------------------------------------ДЩ

Программа может подсоединиться к ORACLE несколько раз. Функция
ORLON устанавливает параллельную связь между ORACLE и програм-
мой пользователя.

Связь осуществляется через две специальные области данных, оп-
ределенные  в программе пользователя - LDA (logon data area) и
HDA (host data  area).  Подпрограмма  ORLON  связывает  LDA  и
ORACLE.

HDA -  это  область  размером  в 256 байт,  связанная с каждым
подсоединением к базе,  осуществленным через обращение к функ-
ции ORLON. Ее использует только ORACLE, однако она должна быть
выделена в программе пользователя,  так же как и LDA и область
данных курсора (cursor data area). Каждое параллельное подсое-
динение требует своей пары LDA-HDA.

Если после обращения к ORLON будет вызвана функция OLOGOF,  то
все  то  все  неподтвержденные  еще  транзакции подтверждаются


                                   - 134 -

(т.е.  соответствующие им изменения в базе  данных  становятся
постоянными).  Если программе пользователя не удается отсоеди-
ниться,  или она аварийно завершается, то все неподтвержденные
еще  транзакции анулируются (т.е.  анулируются соответствующие
им изменения в базе данных).

LDA - это область данных размером в 64 байта,  определенная  в
программе  пользователя.  Число в формате short binary integer
(короткое двоичное целое) в начале этой области  содержит  код
завершения,  показывающий чем кончилось обращение к ORLON. Ну-
левой код завершения означает что подсоединение к ORACLE прош-
ло нормально. Коды завершения, соответствующие возникшим ошиб-
кам перечислены в книге "Сообщения об Ошибках ORACLE и их  Ко-
ды" (ORACLE Error Messages and Codes Manual).

lda (адрес) - адрес 64-байтовой области связи (logon data area),
              определенной в программе пользователя.

hda (адрес) - адрес 256-байтовой области HDA.

uid (адрес) - адрес символьной строки,  содержащей имя пользо-
              вателя и может быть пароль.  Если пароль  содер-
              жится в uid,  то он должен быть отделен от имени
              пользователя символом "/".

uilen (двоичное целое число)
            - длина строки, на которую указывает uid. Если эта
              строка  оканчивается  нулевым символом,  то этот
              параметр можно опустить.

psw (адрес) - адрес пароля. Если пароль входит в параметр uid,
              то параметр psw не требуется.

pswl (двоичное целое число)
             - длина пароля. Если строка, на которую указывает
               psw, оканчивается нулевым символом, то этот па-
               раметр можно опустить.

audit_flag (двоичное целое число)
            - не поддерживается;  единственное допустимое зна-
              чение двоичный целый 0 (ноль).

Обратитесь также к разделу ORACLE*Net в руководстве по инстал-
ляции  и  руководстве пользователя,  чтобы узнать,  нет ли ка-
ких-либо примечаний и ограничений,  относящихся к Вашей систе-
ме.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к ORLON                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і              olon(lda,hda,uid,-1,(char *)-1,-1,0);            і
А--------------------------------------------------------------ДЩ
.


                                   - 135 -


ФУНКЦИЯ OOPEN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і CALL OOPEN ( cursor, lda [,dbn, dbnlen] [,areasize]           і
і                                              [,uid, uidlen] );і
А--------------------------------------------------------------ДЩ

Функция OOPEN организует (открывает) курсор, для передачи опе-
раторов SQL из программы ползователя в ORACLE.

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

Курсор может управлять только одним оператором SQL одновремен-
но. Тот же самый курсор можно использовать для управления дру-
гим оператором SQL,  но предварительно надо связать его с этим
оператором, снова обратившись к подпрограмме OSQL3.

В программе пользователя может быть несколько активных  опера-
торов SQL (несколько курсоров) одновременно. Для этого в прог-
рамме надо выделить несколько курсоров,  обратившись к функции
OOPEN несколько раз.

Область данных  курсора (cursor data area) содержит информацию
о состоянии активной операции  SQL.  Все  прочие  подпрограммы
ORACLE, имеющие дело с оператором SQL, ссылаются на него через
имя соответствующего курсора.  Первые два байта курсора содер-
жат  код завершения,  показывающий результат выполнения OOPEN.
Нулевой код завершения означает,  что OOPEN  успешно  заверши-
лась. Коды завершения, соответствующие возникшим ошибкам пере-
числены в книге  "Сообщения  об  Ошибках  ORACLE  и  их  Коды"
(ORACLE Error Messages and Codes Manual).

cursor (адрес)
              - адрес 64-байтовой области данных курсора,  вы-
                деляемой  в  программе  пользователя.  Функция
                OOPEN связывает эту область с ORACLE.

lda (адрес)
              - адрес области связи, указанной при обращении к
                подпрограмме OLON.

dbn (адрес)   - Не используется.  Включен только для совмести-
                мости с версией 2 ORACLE.

dbnlen (адрес)- Не используется.  Включен только для совмести-
                мости с версией 2 ORACLE.

areasize (двоичное целое число)
              - Этот  дополнительный параметр используется для
                указания размера рабочей  области  SQL  ORACLE
                (SWA  -  SQL Work Area или context area),  для
                изменения  того,  который  эта  область  имеет
                по-умолчанию (размер этой области по-умолчанию
                определяется в файле  инициализации  ORACLE  -
                INIT.ORA).  Если  указанный размер находится в


                                   - 136 -

                пределах от 1 до 128,  он интерпретируется как
                количество  блоков по 1024 байта (т.е.  факти-
                ческий размер области в байтах  будет  в  1024
                раз больше). Если указанный размер больше 128,
                то он интерпретируется просто  как  количество
                байт, занимаемых областью SWA. SWA должна быть
                достаточно большой, чтобы вместить скомпилиро-
                ванный оператор SQL плюс одну строку обрабаты-
                ваемой  таблицы  или  концептуального  разреза
                данных  (view).  Максимальный  размер этой об-
                ласти зависит от операционной системы, под уп-
                равлением  которой работает ORACLE.  Подробнее
                об этом см. в Руководстве по Инсталляции и Ру-
                ководстве  Пользователя для Вашей операционной
                системы.  Минимальный размер SWA -  3072  (3K)
                байта.  Дальнейшее  описание  рабочих областей
                SQL ORACLE см. в главе об "Областях данных ин-
                терфейса  с языками программирования" (в главе
                8).

uid (адрес)
              - адрес символьной строки,  содержащей имя поль-
                зователя и пароль.  Пароль должен быть отделен
                от имени пользователя символом "/".

         Имя пользователя   надо  указывать  при  обращении  к
         OOPEN, если связь с ORACLE была установлена с помощью
         функции OLOGON, присутствовавшей в Версии 2. Если для
         связи с ORACLE использовалась функция  OLON,  то  при
         обращении  к  OOPEN  параметры uid и uidlen игнориру-
         ются.

uilen (двоичное целое число)
              - длина строки,  на которую указывает uid.  Если
                эта строка оканчивается нулевым  символом,  то
                этот параметр можно опустить.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OOPEN                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і        oopen (curs,lda,(char *)-1,-1,-1,(char *)-1, -1);      і
А--------------------------------------------------------------ДЩ



ФУНКЦИЯ OSQL3
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і         CALL OSQL3 ( cursor, sqlstatement [,sqlen] )          і
А--------------------------------------------------------------ДЩ

Функция OSQL3 связывает оператор SQL с открытым курсором и пе-
редает этот оператор в ORACLE для обработки.  Все прочие подп-
рограммы  для  обозначения  оператора SQL используют имя соот-
ветствующего курсора.  Один и тот же курсор  может  последова-
тельно  встречаться  в  разных  обращениях к OSQL3.  Программа
пользователя может также определить несколько курсоров  парал-
лельно.


                                   - 137 -

В качестве  оператора  SQL может фигурировать любой допустимый
запрос SQL, оператор манипулирования данными, оператор опреде-
ления данных или оператор управления данными.  ORACLE осущест-
вляет синтаксический разбор оператора и  выбирает  оптимальный
путь  доступа  (optimal  access path) для выполнения требуемой
функции.  Однако сама операция выполняется только  при  вызове
функции OEXEC.

Коды синтаксических ошибок SQL возвращаются в виде кода завер-
шения в области данных курсора и указателя (в виде смещения от
начала  текста оператора) на то место в тексте оператора,  где
возникла ошибка.  Список информационных полей,  находящихся  в
области данных курсора после обращения к OSQL3, см. в описании
области данных курсора.  Коды завершения, соответствующие воз-
никшим  ошибкам  перечислены  в  книге  "Сообщения  об Ошибках
ORACLE и их Коды" (ORACLE Error Messages and Codes Manual).

cursor (адрес)- адрес  64-байтовой  области данных в программе
                пользователя.  Область данных курсора содержит
                информацию  о состоянии активной операции SQL.
                Каждый курсор определяет в программе пользова-
                теля открытый оператор SQL.

sqlstatement (адрес)
              - адрес символьной строки,  содержащей некоторый
                допустимый оператор SQL.  В любом месте  этого
                оператора,  где  допускаются константы,  могут
                стоять подставляемые переменные  (substitution
                variables). Заменяемые переменные обозначаются
                двоеточием перед именем переменной,  например,
                :EMPNO.   Впоследствие,   при  вызове  функций
                OBNDRN или OBNDRV,  можно указывать заменяемые
                переменные пользуясь их именами.

sqllen (двоичное целое число)
              - длина оператора SQL.  Если символьная  строка,
                содержащая  оператор оканчивается нулевым сим-
                волом, то этот параметр можно опустить.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OSQL3                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і       if ( osql3 (curs,"SELECT ENAME,JOB FROM EMP",-1) );     і
А--------------------------------------------------------------ДЩ



ФУНКЦИЯ ODSC
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і CALL ODSC (cursor,position [,dbsize] [,fsize] [,rcode]        і
і                                    [,cbuf [,cbufl]] [,dsize]) і
А--------------------------------------------------------------ДЩ

Функция ODSC используется,  в основном, для запросов SQL (опе-
раторов SELECT). Она возвращает внутренний тип данных и размер
информации  поля  или выражения в списке выбора (select- list)
запроса.


                                   - 138 -

Поле для ODSC (при каждом обращении эта функция работает толь-
ко с одним полем) идентифицируется номером (позицией) в списке
выбора. При этом считается, что все поля занумерованы в списке
выбора последовательно, слева направо, начиная с единицы.

Использовать ODSC  можно  после  обращений  к OSQL,  OEXEC или
OFETCH, чтобы определить максимальные размеры, внутренние типы
данных (dbsize и dbtype) полей,  возвращаемых в результате вы-
полнения запроса,  а также имена столбцов,  которые  им  соот-
ветствуют. Если ODSC используется после OFETCH, то может также
возвращаться фактический размер (fsize) только что извлеченно-
го (fetched) поля.

Если указанный пользователем номер позиции превышает количест-
во полей в списке выбора,  то в поле кода завершения в области
данных   курсора  ODSC  возвращает  признак  конца  извлечения
(end-of-fetch indicator).  ODSC позволяет  программам  динами-
чески  определять  сколько  полей должно быть возвращено в ре-
зультате выполнения запроса,  что необходимо,  если  программе
заранее неизвестно количество полей в списке выбора, как, нап-
ример, в случае SELECT *.

cursor (адрес)
              - адрес  64-байтовой  области данных в программе
                пользователя.  Имя  курсора  используется  для
                указания ODSC оператора SQL, переданного ранее
                в ORACLE с помощью функции OSQL. Поле кода за-
                вершения  в  области данных курсора показывает
                успешное (нулевое значение) или ошибочное (не-
                нулевое   значение)   завершение  подпрограммы
                ODSC. Коды завершения, соответствующие возник-
                шим  ошибкам перечислены в книге "Сообщения об
                Ошибках  ORACLE  и  их  Коды"  (ORACLE   Error
                Messages and Codes Manual).

position (двоичное целое число)
              - позиция поля или  выражения  в  списке  выбора
                запроса SQL.  Поля и выражения в списке выбора
                разделяются запятыми.  Каждое поле или выраже-
                ние обозначается номером позиции,  получающмся
                при последовательной их нумерации слева напра-
                во,  начиная с единицы. Если указанный пользо-
                вателем номер позиции превышает количество по-
                лей в списке выбора,  то ODSC возвращает приз-
                нак   конца   извлечения   (end-of-fetch   in-
                dicator) в поле кода завершения в области дан-
                ных курсора.

dbsize (адрес)- адрес  переменной  тиапа  short binary integer
                (короткое двоичное целое), которая примет зна-
                чение,  равное  максимальному размеру поля,  в
                соответствии со    Словарем    Данных    (Data
                Dictionary).  Если поле определено,  как  CHAR
                или NUMBER, то возвращаемая длина равна макси-
                мальной длине, указанной для этого поля.

fsize (адрес) - Этот параметр имеет смысл только если ODSC вы-
                зывается после OFETCH.  Он указывает адрес пе-
                ременной типа short binary integer,  в которую
                будет помещена фактическая длина хранящегося в
                базе данных значения, извлеченного при послед-


                                   - 139 -

                нем обращении к функции  OFETCH.  Возвращаемая
                фактическая  длина  хранящегося  в базе данных
                значения есть его длина до помещения  в  буфер
                пользователя,  т.к.  при помещении его в буфер
                могло иметь место отсечение  непомещающейся  в
                буфер части этого значения или,  наоборот, до-
                полнение его концевыми  пробелами.  Перед  за-
                писью значений в базу данных ORACLE отбрасыва-
                ет нули в начале числовых  данных  и  концевые
                пробелы в символьных.

rcode (адрес) - адрес переменной типа short binary integer,  в
                которую будет помещен код завершения последней
                операции  извлечения  (fetch).  Этот  параметр
                имеет смысл, только если ODSC вызывается после
                OFETCH.

dbtype (адрес)- адрес переменной типа short binary integer,  в
                которую будет помещен  внутренний  тип  данных
                поля,  в соответствии со Словарем Данных (Data
                Dictionary). Поля, определенные как CHAR, хра-
                нятся в виде символьных строк переменной длины
                и для них возвращаемое значение равно
                1. Поля  определенные  как  NUMBER хранятся во
                внутреннем  формате   масштабированных   целых
                чисел  ORACLE  и для них возвращаемое значение
                равно 2.  Для полей, содержащих результаты вы-
                ражений, возвращаемое значение также равно
                2. Поля, определенные как DATE, хранятся в ви-
                де ГГГГММ--ЧЧММСС и для них возвращаемое  зна-
                чение равно 12.

cbuf (адрес)  - адрес буфера поля данных в программе пользова-
                теля, в который помещается имя столбца или вы-
                ражение.  Если cbuf равен 0, то имя столбца не
                записывается.

cbufl (адрес) - адрес переменной типа  short  binary  integer,
                содержащего длину cbuf.  Если имя столбца, ко-
                торое надо поместить в буфер, длинее cbufl, то
                часть  имени  будет  отсечена.  При выполнении
                QDSC в cbufl  помещается  значение  в  формате
                short  binary  integer,  представляющее  собой
                длину имени столбца,  занесенного в cbuf. Если
                cbufl не указан, или равен нулю, то имя столб-
                ца не записывается.

dbsize (адрес) - адрес переменной типа short binary integer, в
                 которую будет помещен максимальный размер по-
                 ля при выводе (display size), когда оно возв-
                 ращается в виде символьной строки. dsize осо-
                 бенно  полезен,  когда  используются  функции
                 вроде  SUBSTR  или  TO_CHAR,  чтобы  изменить
                 представление столбца.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к ODSC                      і
Г--------------------------------------------------------------Дґ
і     odsc (curs,1,&deptl,(short *)01,(short *)01, (short *)01, і
і           (short *)01,(char *)-1,(short *)-1,(short *)-1);    і
А--------------------------------------------------------------ДЩ


                                   - 140 -



ФУНКЦИЯ ONAME
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і     CALL ONAME (cursor, position, tbuf, tbufl, cbuf, cbufl)   і
А--------------------------------------------------------------ДЩ

Функция ONAME используется  для  извлечения  имен  столбцов  в
списке выбора запроса SQL.  Поле для ONAME (при каждом обраще-
нии эта функция работает только с одним  полем)  идентифициру-
ется  номером (позицией) в списке выбора.  При этом считается,
что все поля занумерованы  в  списке  выбора  последовательно,
слева направо, начиная с единицы.

ONAME можно использовать после вызова функции OSQL,  чтобы оп-
ределить выражения или имена столбцов,  соответствующих полям,
которые надо возвращать.  Максимальная длина имени столбца 240
байтов.

Если указанный пользователем номер позиции превышает количест-
во полей в списке выбора,  то в поле кода завершения в области
данных курсора ONAME возвращает признак  конца  списка  выбора
(end-of-   select-list  indicator).  Используя  признак  конца
списка выбора,  программы могут динамически  определять  имена
полей,  которые  надо  возвращать в результате выполнения зап-
роса, в тех случаях,  когда программе заранее неизвестно коли-
чество полей в списке выбора, как,например, в случае SELECT *.

cursor (адрес) - адрес 64-байтовой области данных в  программе
                 пользователя.  Имя  курсора  используется для
                 указания ONAME оператора SQL, переданного ра-
                 нее в ORACLE с помощью функции OSQL.

position (двоичное целое число)
              - номер  позиции поля или выражения в списке вы-
                бора запроса SQL.  Поля и выражения  в  списке
                выбора   разделяются   запятыми  и  нумеруются
                последовательно слева направо,  начиная с еди-
                ницы. Если указанный пользователем номер пози-
                ции превышает количество полей в списке  выбо-
                ра, то в поле кода завершения в области данных
                курсора ONAME возвращает признак конца  извле-
                чения (end-of-fetch indicator).  ONAME исполь-
                зует номер позиции,  чтобы соотнести буферы  с
                полями в списке выбора.

tbuf (адрес)  - включен  только  для  совместимости  с  ORACLE
                версии 2. Не используется.

tbufl (адрес) - включен  только  для  совместимости  с  ORACLE
                версии 2. Не используется.

cbuf (адрес)  - адрес буфера поля данных в программе пользова-
                теля, в который помещается имя столбца или вы-
                ражение.  Если cbuf равен 0, то имя столбца не
                записывается.

cbufl (адрес) - адрес переменной  типа  short  binary  integer
                (короткое  двоичное целое),  содержащего длину


                                   - 141 -

                cbuf. Если имя столбца, которое надо поместить
                в  буфер,  длинее cbufl,  то часть имени будет
                отсечена. После выполнения ONAME в cbufl будет
                содержаться число   в   формате  short  binary
                integer,  представляющее  собой  длину   имени
                столбца,  занесенного  в  cbuf.  Если cbufl не
                указан,  или равен нулю, то имя столбца не за-
                писывается.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к ONAME                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і         oname (curs[1],2,&table,&tablen,&col,&collen);        і
і                                                               і
А--------------------------------------------------------------ДЩ



ФУНКЦИЯ ODEFIN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і CALL ODEFIN (cursor, pos, buffer, bufl, ftype [,scale]        і
і                     [,fmt] ,fmtl] [,fmtt]] [,retl] [,rcode] ) і
А--------------------------------------------------------------ДЩ

Функция ODEFIN определяет выходные буферы, соответствующие по-
лям в списке выбора запроса SQL  (каждому  полю  соответствует
один  буфер).  При каждом обращении к ODEFIN определяется один
буфер.  Буферы должны определятся после обращения к  OSQL,  но
перед обращением к OFETCH.

С помощью  ODEFIN  указывается  местоположение и размер буфера
поля данных в программе пользователя.  ODEFIN также  позволяет
указать внешний тип данных поля, определяемый программой поль-
зователя и (если пользователь этого хочет) определить перемен-
ную, в которую будет помещаться код завершения на уровне поля.

Буферы выбора  всегда  определяются позиционно.  Поля в списке
выбора,  обозначаются номером позиции в списке, причем зануме-
рованы  они последовательно слева направо,  начиная с единицы.
При выполнении функции OFETCH ORACLE преобразует  каждое  поле
из внутреннего типа данных в указанный внешний тип, после чего
заносит значения полей в соответствующие им буферы (определен-
ные с помощью ODEFIN).

ORACLE возвращает  через область данных курсора код завершения
на уровне строки таблицы  и  дополнительно,  т.е.  по  желанию
пользователя, кода завершения на уровне отдельного поля, через
указанную при вызове  ODEFIN  переменную.  При  каждом  вызове
OFETCH ORACLE устанавливает код завершения для каждого обрабо-
танного поля. Это код показывает было ли поле извлечено успеш-
но  (0) или возникла какая-то исключительная ситуация,  напри-
мер,  было извлечено пустое поле, часть поля была отсечена или
возникла  еще какая-нибудь не критическая ошибка при работе со
столбцом.  Коды завершения на уровне отдельных полей заносятся
в переменные rcode для каждого поля, для которого эта перемен-
ная определена. Коды завершения на уровне полей описаны в кни-
ге  "Сообщения  об  Ошибках  ORACLE  и  их Коды" (ORACLE Error
Messages and Codes Manual).


                                   - 142 -

cursor (адрес) - адрес 64-байтовой области данных в  программе
                 пользователя.  Функция ODEFIN пользуется име-
                 нем курсора,  чтобы связать буфер поля данных
                 с определенным оператором SQL.

pos (двоичное целое число)
              - номер позиции поля или выражения в списке  вы-
                бора запроса SQL.  Поля списке выбора разделя-
                ются  запятыми  и  нумеруются  последовательно
                слева направо, начиная с единицы. Если указан-
                ный пользователем номер позиции превышает  ко-
                личество полей в списке выбора, то в поле кода
                завершения в  области  данных  курсора  ODEFIN
                возвращает  признак  конца файла (end-of- file
                indicator).  ODEFIN использует номер  позиции,
                чтобы соотнести буферы с полями в списке выбо-
                ра.

buffer (адрес) - адрес буфера поля данных в программе  пользо-
                 вателя,  в  который будут помещены данные при
                 обращении к OFETCH.

bufl (двоичное целое число)
              - длина определяемого буфера.

ftype (двоичное целое число)
              - внешний тип данных,  к которому будет преобра-
                зовываться поле перед помещением в буфер поль-
                зователя. Список внешних типов данных приведен
                в главе 11.

scale (двоичное целое число)
              - количество цифр справа от десятичной точки при
                выдаче  полей  типа  7 (упакованные десятичные
                числа КОБОЛа).  Для всех других  типов  данных
                scale игнорируется.

indp (адрес)  - адрес переменной  типа  short  binary  integer
                (короткое двоичное целое), в которую будет по-
                мещаться длина извлеченного поля.

         При обращении к OFETCH значение этой переменной пока-
         зывает,  было ли извлеченное поле усечено,  оставлено
         без  изменений  или  оно  оказалось пустым (NULL),  а
         именно:

         отрицательное значение  Извлеченное поле пусто.

         ноль                    Поле помещено в буфер без
                                 изменений.

         положительное значение  Длина  поля  превышала размер
                                 буфера, поэтому оно было усе-
                                 чено.   Возвращенное  положи-
                                 тельное  значение  при   этом
                                 равно длине поля до усечения.

fmt (адрес)   - адрес строки, содержащей формат преобразования
                (conversion format). В настоящее время исполь-
                зовать этот параметр можно только  если  ftype
                равен 7 (упакованные десятичные числа КОБОЛа).


                                   - 143 -

                Формат имеет вид: "mm.[+/-]nn", где "mm" - об-
                щее  количество  цифр  (от 1 до 38),  а "nn" -
                десятичный масштаб  (например,  09.+02).  Знак
                плюс или минус обязателен. Если указан "+", то
                "nn" - количество цифр  справа  от  десятичной
                точки.  Если  указан  "-",  то  "nn" - порядок
                числа (степень десяти,  на которую надо  умно-
                жать  число  перед помещением его в буфер).  В
                дальнейших реализациях  будут,  возможно,  до-
                пускаться и другие форматы.  Если Ваш компиля-
                тор не позволяет пропускать параметры  или  не
                позволяет передавать тут значение -1, то, что-
                бы указать на отсутствие параметра fmt,  пере-
                давайте  0  в качестве параметра длины формата
                (fmtl).

fmtl (двоичное целое число)
              - длина строки,  содержащей формат  преобразова-
                ния.  Если  fmtl  равно  0,  то  fmt и fmtt не
                используются.

fmtt (двоичное целое число)
              - тип формата преобразования.  В настоящее время
                может принимать только значение 7 (упакованные
                десятичные числа КОБОЛа).  Все другие значения
                игнорируются.

retl (адрес)  - адрес  переменной  типа  short  binary integer
                (короткое двоичное целое),  в  которую  ORACLE
                помещает  фактическую длину извлекаемого поля.
                Эта переменная получает значение после обраще-
                ния к подпрограмме OFETCH.

rcode (адрес) - адрес переменной типа short binary integer , в
                которую  будет помещаться код завершения после
                выполнения подпрограммы OFETCH. Ниже приведены
                коды некоторых ошибок,  возникающих при извле-
                чении поля:

         КОД    ЗНАЧЕНИЕ

         0    все в порядке

         1406 отсечение  символьных  данных.   Преобразованные
         данные из базы не поместились в буфер.

         1454 указано   недопустимое   преобразование:   целые
         числа,  длина которых не равна 1, 2 или 4; веществен-
         ные  числа,  длина которых не 4 и не 8;  недопустимое
         преобразование в упакованные  десятичные  числа;  при
         преобразовании в упакованные десятичные числа указано
         больше 38 цифр.

         1455 переполнение вещественного числа. При преобразо-
         вании поля базы данных получается слишком большое ве-
         щественное число,  которое не укладывается в машинный
         формат вещественных чисел (с плавающей точкой).

         1456 переполнение  целого  числа.  При преобразовании
         поля базы данных в машинный формат целых  чисел  ука-
         занного размера, теряются значащие цифры.


                                   - 144 -

         1457 переполнение десятичного числа. При преобразова-
         нии поля базы данных в упакованное  десятичное  поле,
         теряются значащие цифры.

         3004 требуемое преобразование не поддерживается.  Под
         управлением операционной системы VMS не используется.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к ODEFIN                    і
Г--------------------------------------------------------------Дґ
і                                                               і
і odefin (curs,1,&empno,2,3,-1,(short *)-1,(char *)-1,-1,-1,    і
і                                                &rlen,&rcode); і
А--------------------------------------------------------------ДЩ



ФУНКЦИИ OBNDRV И OBNDRN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і CALL OBNDRV (cursor,sqlvar,sqlvl,progvar,progvl,ftype[,scale] і
і              [,indp][,fmt[,fmtl]],fmtt]])                     і
і CALL OBNDRN (cursor,sqlvarnum,progvar,progvl,ftype[,scale]    і
і              [,indp][,fmt[,fmtl]],fmtt]])                     і
А--------------------------------------------------------------ДЩ

Связующие функции OBNDRV и  OBNDRN  используются  для  динами-
ческого изменения оператора SQL после того, как он был передан
в ORACLE функцией OSQL3. Например, Вам может потребоваться из-
менить   некоторые   значения  в  предложении  WHERE  (скажем,
DEPTNO), чтобы изменить множество выбираемых из таблицы строк.
Оператор  SQL  может  быть  выполнен,  затем изменен с помощью
функций OBNDRV и OBNDRN и снова выполнен в желаемом виде.

Вызовы функций OBNDRV и OBNDRN указывают,  что некоторая вели-
чина в программе должна быть поставлена в соответствие некото-
рой заменяемой переменной в операторе SQL.  Если  эти  функции
используются, то перед обращением к OEXEC они должны быть выз-
ваны по разу для каждой переменной программы.  После обращения
к  этим функциям ORACLE запоминает адрес переменной программы.
Когда переменная программы изменяется,  к этим связующим функ-
циям  не надо обращаться снова.  Поскольку ORACLE хранит физи-
ческую ссылку (абсолютный адрес) на переменную программы,  па-
раметры  progvar  и progval должны быть статически размещены в
памяти (не должны перемещаться).  ORACLE не  подстраивается  к
изменениям  в  размещении переменных в памяти.  Если Вы хотите
использовать другую переменную (а не другое  значение  той  же
самой)  для  подстановки  в оператор SQL,  то надо снова обра-
титься к связующей функции с новым именем переменной.

Функции OBNDRV и OBNDRN почти ничем не различаются,  за исклю-
чением способа, которым они идентифицируют заменяемые перемен-
ные в операторе SQL.  OBNDRN  идентифицирует  их  по  номерам.
OBNDRV - по именам.  Имя связываемой переменной не должно сов-
падать ни с одним из зарезервированных слов ORACLE.

В процессе связывания ORACLE преобразует переменную  программы
из внешнего формата во внутренний, после чего помещает ее зна-
чение в оператор SQL. OBNDRV и OBNDRN вызываются после обраще-
ния к OSQL3 и до обращения к OEXEC. Если одна и та же заменяе-


                                   - 145 -

мая переменная встречается в списке выбора более одного  раза,
то  одно  обращение к OBNDRV или OBNDRN свяжет все ее встреча-
ния.  Количество установленных связей возвращается в поле ука-
зателя  на  синтаксическую ошибку (Parse Error Offset field) в
области данных курсора.

Код завершения процесса связывания возвращается  в  поле  кода
завершения  в  области  данных курсора.  Коды возможных ошибок
описаны в книге  "Сообщения  об  Ошибках  ORACLE  и  их  Коды"
(ORACLE Error Messages and Codes Manual). Если возникает ошиб-
ка преобразования символьных данных в числовые  (код  +5),  то
процесс  связывания  прерывается  с  кодом +5.  Если возникает
ошибка ORACLE,  код которой отрицателен (например,  -625 -  не
поддерживаемое преобразование), то процесс связывания прерыва-
ется и поле местоположения синтаксической ошибки (Parse  Error
Offset field)  в области данных курсора будет указывать на но-
мер встречания имени переменной, где возникла ошибка. Если за-
меняемое  имя  не  существует,  то  возвращается ошибка ORACLE
-605.

cursor (адрес)
              - адрес  64-байтовой  области данных в программе
                пользователя.  Функции   OBINDRV   и   OBINDRN
                используют имя курсора,  для обозначения опре-
                деленного оператора SQL.

sqlvar (адрес)
              - Используется только при вызове OBNDRV,  указы-
                вает адрес символьной строки,  содержащей  имя
                заменяемой пере-менной в операторе SQL. В опе-
                раторе SQL перед именем переменной стоит двое-
                точие,   т.е.,   например:   WHERE   EMPNO   =
                :EMPLOYEE. OBNDRV помещает значение переменной
                программы в заменяемую переменную :EMPLOYEE.

sqlvl (двоичное целое число)
              - Используется только при вызове OBNDRV,  указы-
                вает длину символьной строки,  на которую ука-
                зывает sqlvar. Например, длина :EMPLOYEE равна
                9.  Если  после  имени заменяемой переменной в
                строке стоит нулевой символ,  то этот параметр
                можно опустить.

sqlvarnum (двоичное целое число)
              - Используется только при вызове OBNDRN,  указы-
                вает  номер заменяемой переменной в том опера-
                торе SQL,  на который указывает курсор. Напри-
                мер,  если sqlvarnum равен 2,  он указывает на
                заменяемую переменную  SQL,  определяемую  как
                :2.

progvar (адрес)
              - адрес  переменной,  определленой  в  программе
                пользователя,  значение  которой  будет извле-
                каться при выполнении OEXEC.  Адрес этой пере-
                менной  ORACLE  запоминает в процессе связыва-
                ния.

progvl (двоичное целое число)
              - длина переменной программы. Поскольку связыва-
                ние переменной делается один раз,  этот  пара-


                                   - 146 -

                метр   должен   содержать  максимальную  длину
                progvar.  Чтобы связать с переменной программы
                пустое  значение (NULL),  используйте параметр
                indp.

ftype (двоичное целое число)
              - тип данных переменной, определенный в програм-
                ме.  Прежде чем связать переменную программы с
                оператором SQL, ORACLE преобразует ее из внеш-
                него формата во внутренний.  Внешние типы дан-
                ных и их коды приведены в главе 11.

scale (двоичное целое число)
              - количество цифр справа от десятичной точки для
                полей  типа 7 (упакованные десятичные КОБОЛа).
                Для всех других типов данных этот параметр иг-
                норируется.

indp (адрес) - адрес переменной типа short binary integer, по-
               казывающей,  является ли подставляемое значение
               пустым.  Если при обращении к OEXEC indp указы-
               вает на отрицательное число,  значит значение в
               соответствующем  столбце  таблицы (поле) должно
               быть пустым (NULL);  в  противном  случае,  это
               значение  берется  из  того места памяти,  куда
               указывает progvar длины progvl.

fmt (адрес)   - адрес  символьной  строки,  содержащей  формат
                преобразования (conversion format).  В настоя-
                щее  время  использовать  этот  параметр можно
                только если ftype равен 7  (упакованные  деся-
                тичные   числа   КОБОЛа).  Формат  имеет  вид:
                "mm.[+/-]nn", где "mm" - общее количество цифр
                (от  1  до  38),  а  "nn" - десятичный масштаб
                (например, 09.+02). Знак плюс или минус обяза-
                телен.  Если указан "+",  то "nn" - количество
                цифр справа от десятичной точки.  Если  указан
                "-",  то "nn" - порядок числа (степень десяти,
                на которую надо умножать число перед помещени-
                ем его в буфер).  В дальнейших реализациях бу-
                дут,  возможно,  допускаться и другие форматы.
                Если  Ваш  компилятор  не позволяет пропускать
                параметры или не позволяет передавать тут зна-
                чение -1,  то, чтобы указать на отсутствие па-
                раметра fmt, передавайте 0 в качестве парамет-
                ра длины формата (fmtl).

fmtl (двоичное целое число)
              - длина  строки,  содержащей формат преобразова-
                ния.  Если fmtl равно 0,  то  fmt  и  fmtt  не
                используются.

fmtt (двоичное целое число)
              - тип формата преобразования.  В настоящее время
                может принимать только значение 7 (упакованные
                десятичные числа КОБОЛа).  Все другие значения
                игнорируются.
.


                                   - 147 -

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OBNDRV                    і
Г--------------------------------------------------------------Дґ
і                                                               і
і obndrv (curs,":ENAME",-1,strings,-1,1,-1,(short *)-1,         і
і                                            (char *)-1,0,0);   і
А--------------------------------------------------------------ДЩ



ФУНКЦИЯ OOPT
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і           CALL OOPT (cursor, rollbackopt, waitopt)            і
А--------------------------------------------------------------ДЩ

Функция OOPT используется для установки:

*  параметра удаления из базы  внесенных  изменений  (удаления
   транзакции  (rollback))  при  возникновении  не критических
   (non- fatal) ошибок  ORACLE,  связанных  с  многостроковыми
   операторами SQL INSERT и UPDATE.

*  параметра ожидания в случаях,когда требуемые ресурсы не мо-
   гут быть предоставлены - например,  ждать ли снятия  блоки-
   ровки (lock) строк таблицы, или других блокировок.

cursor (адрес)- адрес 64-байтовой области данных в программе
                пользователя.

rollback (двоичное целое число)
              - указывает,  что  делать в случае возникновения
                не критической ошибки  ORACLE.  Если  значение
                этого параметра равно 0, то в случае возникно-
                вения любых ошибок, даже не критических, теку-
                щая транзакция анулируется. Если значение это-
                го параметра равно  2,  то  анулированы  будут
                лишь изменения, внесенные в ту строку таблицы,
                в  которой  возникла  не  критическая  ошибка.
                Именно  такое  значение  имеет  этот  параметр
                по-умолчанию.  Биты  FLAG2  в  области  данных
                курсора  показывают  была  ли возникшая ошибка
                критической.

waitopt (двоичное целое число)
              - указывает,  ждать  ли  освобождения  ресурсов.
                Если значение  этого  параметра  равно  0,  то
                программа ждет, пока ресурс освободится. Такое
                значение этот  параметр  имеет  по  умолчанию.
                Если  значение  этого  параметра  равно 4,  то
                программа получит  ошибочный  код  завершения,
                если требуемый ресурс не может быть немедленно
                предоставлен.  Такая установка этого параметра
                может привести к большому количеству ошибочных
                кодов  завершения,  возникающих  при  ожидании
                внутренних  ресурсов заблокированных на корот-
                кое время.  Ошибки  связанные  с  возможностью
                использования ресурсов генерируются только для
                ресурсов   требуемых   вызывающему    процессу
                (calling process).


                                   - 148 -

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OOPT                      і
Г--------------------------------------------------------------Дґ
і                                                               і
і                      oopt (curs,2,4);                         і
А--------------------------------------------------------------ДЩ



ФУНКЦИЯ OEXEC
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                     CALL OEXEC (cursor)                       і
А--------------------------------------------------------------ДЩ

Функция OEXEC вызывает выполнение оператора SQL,  связанного с
указываемым курсором.

Перед обращением к OEXEC должна быть успешно выполнена функция
OSQL3  или  OSQL.  Если соответствующий курсору оператор SQL -
запрос, то перед обращением к OEXEC с каждым полем или выраже-
нием  в  нем должна быть связана какая-нибудь переменная прог-
раммы. Если в оператор SQL входят какие-нибудь программные пе-
ременные,  то перед обращением к OEXEC с ними должны быть свя-
заны какие-нибудь  значения.  Связываемые  с  помощью  функций
OBNDRV  и OBNDRN данные передаются в ORACLE,  когда вызывается
функция OEXEC. Затем программа пользователя должна явно потре-
бовать каждую строку результата, используя функцию OFETCH.

Если соответствующий  курсору оператор SQL есть оператор мани-
пулирования данными,  оператор определения данных или оператор
управления данными,  то,  при обращении к OEXEC,  вся операция
выполняется целиком. При этом устанавливается поле кода завер-
шения в области данных курсора,  а в поле счетчика строк поме-
щается количество обработанных оператором строк таблицы.

Если какая-то строка таблицы была отвергнута  из-за  возникшей
ошибки и параметру rollback в функции OOPT было присвоено зна-
чение 2,  то из базы удаляются лишь изменения, внесенные в эту
строку. Если же параметр rollback имеет значение 0, то из базы
будут удалены все внесенные в нее изменения (будет анулирована
(rolled back) текущая транзакция).

cursor (адрес)- адрес 64-байтовой области данных в программе
                пользователя.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OEXEC                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і                       oexec (curs);                           і
А--------------------------------------------------------------ДЩ

.


                                   - 149 -


ФУНКЦИЯ OEXN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                CALL OEXN (cursor,count,offset);               і
А--------------------------------------------------------------ДЩ

где:
cursor (адрес)- адрес 64-байтовой области данных в программе
                пользователя.

count (двоичное целое число)
              - размер массива связанных переменных,  значения
                из которого  будут  подставляться  в  оператор
                SQL.

offset (двоичное целое число)
              - смещение (offset) от начала массива  связанных
                переменных,  с  которого  начинают  выбираться
                значения.

Функция OEXN позволяет выполнять  операции,  используя  массив
связанных переменных.  Каждая заменяемая переменная, связанная
с переменной программы с помощью функций OBNDRV и OBNDRN, есть
первый элемент массива связанных переменных. Например в следу-
ющем фрагменте программы на СИ:

    int progvar1[10];
    char progvar2[10][50];
    OSQL3(cursor,"INSERT INTO TBL1 VALUES (:VAR1, :VAR2)", -1);
    OBNDRV(cursor, "var1", -1, progvar1[0], 4, 3, ...);
    OBNDRV(cursor, "var2", -1, progvar2[0], 50, 1, ...);

описано два массива:  один из 10 целых чисел,  другой - из  10
строк, по 50 символов в каждой, и открыт оператор SQL, который
можно использовать для вставки сразу нескольких строк в табли-
цу. Пользователь может добавлять данные в таблицу двумя спосо-
бами:   добавлять   по   одной   строке,   используя   функцию
OEXEC(cursor) (при этом добавляемые значения должны находиться
в progvar1[0] и progvar2[0]),  либо добавить сразу  10  строк,
используя функцию OEXN(cursor, 10,0) (при этом первая пара до-
бавляемых  значений  должна   находиться   в   progvar1[0]   и
progvar2[0],  вторая  пара  -  в  progvar1[1]  и progvar2[1] и
т.д.).

Код завершения OEXN возвращается в поле кода завершения в  об-
ласти  данных курсора.  Значение в поле счетчика строк,  в об-
ласти данных курсора, показывает количество успешно обработан-
ных строк. Если это значение (обозначим его за n) не совпадает
с парамтром count в обращении к OEXN,  значит ошибка  возникла
при обработке (n+1)-ой строки. Если не транзакция не была ану-
лирована (см.  flags1 в описании области данных  курсора),  то
пользователь может продолжить прерванную операцию, изменив па-
раметр offset,  чтобы начать операцию не с первыми  элементами
массива,  и соответственно изменив параметр count. Если в при-
веденном выше примере счетчик обработанных строк после  завер-
шения  OEXN оказался равным 5,  значит ошибка возникла при до-
бавлении 6-ой строки.  Чтобы продолжить  операцию,  начиная  с
7-ой строки, надо обратиться к OEXN таким образом:


                                   - 150 -

       OEXN(cursor, 3, 7);  /* добавить 3 элемента массива,
                               начиная с седьмого (progvar1[6]
                               и progvar2[6])               */



ФУНКЦИЯ ORES
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                      CALL ORES (cursor)                       і
А--------------------------------------------------------------ДЩ

Функция ORES больше не поддерживается.




ФУНКЦИЯ OFETCH
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                     CALL OFETCH (cursor)                      і
А--------------------------------------------------------------ДЩ

Функция OFETCH  извлекает  в  программу  пользователя  строки,
составляющие результат выполнения запроса, по одной строке за-
одно обращение.  Каждое поле запроса помещается в буфер, опре-
деленный ранее с помощью подпрограммы  ODEFIN.  Поля,  которые
программа пользователя требует с символьном формате,  выравни-
ваются по левому краю и дополняются концевыми пробелами.  Сим-
вольные  строки,  которые  не помещаются в буфер,  отсекаются,
причем в этом случае и код завершения для данного поля  и  код
завершения в области данных курсора принимают значение +3.

Если при извлечении какое-либо поле оказывается пустым (содер-
жит пустое данное (NULL)),  то код завершения для данного поля
принимает значение +2, а буфер пользователя остается без изме-
нений.  Чтобы определить,  какие именно поля  содержат  пустые
данные или были усечены,  программа пользователя должна была с
помощью функции ODEFIN определить либо переменные,  в  которые
будут помещаться коды завершения полей либо индикаторные пере-
менные (indicator variables) или она может обращаться к  функ-
ции ODSC после вызова OFETCH.

Во время  последовательного извлечения с помощью OFETCH строк,
выбранных из таблицы в результате выполнения запроса, в курсо-
ре хранится указатель на текущюю строку. После каждого обраще-
ния к OFETCH пересчитывается поле  счетчика  строк  в  области
данных курсора. Извлекаются строки последовательно. Нет спосо-
ба снова извлечь уже извлеченные строки,  кроме как  выполнить
еще раз соответствующий запрос, вызвав OEXEC, после чего дойти
до нужной строки,  последовательно  извлекая  все  предыдущие.
После извлечения последней строки, входящей в результат выпол-
нения запроса,  попытка извлечь еще одну строку будет  возвра-
щать  код  завершения  =4  -  признак конца файла (end-of-file
indicator).  По достижении конца файла в поле  счетчика  строк
содержится общее число строк,  выбранных из таблицы при выпол-
нении запроса.


                                   - 151 -

cursor (адрес)- адрес 64-байтовой области данных в программе
                пользователя.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OFETCH                    і
Г--------------------------------------------------------------Дґ
і                                                               і
і                      ofetch (curs);                           і
А--------------------------------------------------------------ДЩ



ФУНКЦИЯ OFEN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                  CALL OFEN (cursor, count)                    і
А--------------------------------------------------------------ДЩ

где:

cursor (адрес)
              - адрес 64-байтовой области данных в программе
                пользователя.

count (двоичное целое число)
              - размер  массива  выходных  переменных  (define
                variables),  в который будут помещаться извле-
                каемые значения.

Функция OFEN позволяет программам  извлекать  сразу  несколько
строк в массив выходных переменных (define variables). Она по-
хожа на функцию OFETCH,  которая извлекает только одну  строку
из результата выполнения запроса.  Каждая выходная переменная,
описанная с помощью функции ODEFIN  или  ODEFINN  есть  первый
элемент массива. Например в следующем фрагменте программы:

      int progvar1[10];
      char progvar2[10];
      OSQL3 (cursor, "SELECT VAR1, VAR2 TBL1", -1);
      ODEFIN (cursor, 1, progvar1[0], 4, 3, ...);
      ODEFIN (cursor, 1, progvar2[0], 50, 1, ...);

описано два  массива:  один из 10 целых чисел,  другой - из 10
строк, по 50 символов в каждой, и открыт оператор SQL, который
можно использовать для выбора нескольких строк из таблицы базы
данных.  Пользователь может извлекать строки,  входящие в  ре-
зультат выполнения запроса двумя способами: извлекать по одной
строке, используя функцию OFETCH(cursor) (при этом извлекаемые
значения всегда будут помещаться в progvar1[0] и progvar2[0]),
либо извлечь сразу 10 строк (или  меньше),  используя  функцию
OFEN(cursor,  10)  (при  этом первая пара извлекаемых значений
будет помещаться в progvar1[0] и progvar2[0],  вторая пара - в
progvar1[1] и progvar2[1] и т.д.).

Код завершения  OEXN возвращается в поле кода завершения в об-
ласти данных курсора.  Значение в поле счетчика строк,  в  об-
ласти  данных курсора показывает количество успешно обработан-
ных строк с момента выполнения OEXEC (т.е.  этот счетчик куму-
лятивный (накапливает значения)).  Если это значение не совпа-
дает с парамтром count в обращении  к  OFEN,  значит  возникла


                                   - 152 -

ошибка,  например,  все строки извлечены (END OF FETCH).  Если
какие-то строки остались  неизвлеченными,  то  операцию  можно
продолжить, при этом извлекаемые строки будут снова помещаться
в массив, начиная с первого элемента.




ФУНКЦИЯ OBREAK
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                       CALL OBREAK (lda)                       і
А--------------------------------------------------------------ДЩ

Функция OBREAK используется для асинхронного прерывания какой-
либо функции ORACLE. Главным образом, эта функция используется
для прерывания долго длящихся функций OEXEC и OFETCH.  Впрочем
она прервет и любую другую функцию ORACLE, которая выполняется
в момент обращения к OBREAK. Любая выполняемая ORACLE функция,
связанная с указанной областью LDA,  не успевшая завершиться к
моменту вызова OBREAK, будет прервана.

Если в момент вызова OBREAK никакая функция не является актив-
ной,  то  просто ничего не произойдет,  за исключением случая,
когда вслед за этим вызывается функция OFETCH.

OBREAK это функция ORACLE, которая может быть вызвана во время
работы  какой-то  другой функции ORACLE.  Не надо обращаться к
этой функции,  когда работают функции OLON,  ORLON или OLOGOF,
поскольку при этом LDA находится в неопределенном состоянии.

После выполнения  OBREAK  код ошибки не может быть возвращен в
LDA,  поскольку эта функция может быть вызвана в момент, когда
структуры внутреннего статуса ORACLE,  могут находиться в про-
тиворечивом состоянии. Если язык, на котором написана вызываю-
щая программа, поддерживает коды завершения функций (это дела-
ют,  например,  ФОРТРАН и СИ),  то OBREAK будет возвращать код
ошибки ORACLE в виде кода завершения функции.

lda (адрес)   - адрес области  LDA,  которая  была  связана  с
                ORACLE  при подсоединении к нему (например,  с
                помощью функции OLON).

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OBREAK                    і
Г--------------------------------------------------------------Дґ
і                                                               і
і                       obreak (lda);                           і
А--------------------------------------------------------------ДЩ




ФУНКЦИЯ OCAN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                        CALL OCAN (cursor)                     і
А--------------------------------------------------------------ДЩ


                                   - 153 -

Функция OCAN сообщает ORACLE,  что текущая операция, связанная
с указанным курсором, завершена.

Например, если курсор используется для синтаксического разбора
оператора SQL,  в результате выполнения которого из базы будет
извлечено  неопределенное  число строк,  но пользователю нужна
только первая из них,  то после выполнения OEXEC и  извлечения
первой  строки  с помощью OFETCH,  используя функцю OCAN можно
сообщить ORACLE,  что программа пользователя больше  не  будет
обращаться  к  OFETCH до тех пор пока снова не будет выполнена
функция OEXEC.

ORACLE использует OCAN,  чтобы освободить ресурсы,  занимаемые
незавершенной  операцией,  включая  и  место занимаемое файлом
before image.

Использовать функцию OCAN можно в любом месте программы, когда
когда все требуемые строки уже извлечены,  но признак того что
все строки извлечены (end-of-fetch) (код завершения +4) так  и
не встретился.

cursor (адрес)- адрес 64-байтовой области данных курсора, свя-
                занной с оператором SQL функцией OOPEN.

Ъ--------------------------------------------------------------Дї
і                   Пример обращения к OCAN                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і                         ocan(curs);                           і
А--------------------------------------------------------------ДЩ




ФУНКЦИЯ OCOM
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                        CALL OCOM (lda)                        і
А--------------------------------------------------------------ДЩ

Функция OCOM делает постоянными последние внесенные в базу из-
менения (подтверждает текущую транзакцию).

Текущая транзакция (т.е.  "последние внесенные изменения") на-
чинается с момента обращения к подпрограмме OLON или с послед-
него обращения к OROL или OCOM и  продолжается  до  следующего
вызова OCOM,  OLROL или OLOGOF. Если функция OCOM аварийно за-
вершается,  то в первые два байта области данных связи (LDA  -
logon data area) помещается код,  по которому можно определить
причину аварийного завершения OCOM.

lda (адрес)   - адрес  области  LDA,  которая  была  связана с
                ORACLE при подсоединении к нему  (например,  с
                помощью функции OLON).

Не путайте функцию OCOM (COMMIT WORK -  подтвердить  внесенные
изменения) с функцией OCON (то же самое, что SET AUTOCOMMIT ON
- установить режим автоматического подтверждения транзакций).


                                   - 154 -

Ъ--------------------------------------------------------------Дї
і                   Пример обращения к OCOM                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і                         ocom(lda);                            і
А--------------------------------------------------------------ДЩ




ФУНКЦИЯ OROL
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                        CALL OROL (lda)                        і
А--------------------------------------------------------------ДЩ

Функция OROL  удаляет  из  базы  последние внесенные изменения
(анулирует текущую транзакцию).

Текущая транзакция - это группа операторов SQL,  выполненных с
момента  обращения  к  функции OLON или последнего обращения к
OCOM или OROL.  Если функция OROL аварийно завершается,  то  в
первые  два байта области данных связи (LDA - logon data area)
помещается код, по которому можно определить причину аварийно-
го завершения OROL.

lda (адрес)   - адрес области  LDA,  которая  была  связана  с
                ORACLE  при подсоединении к нему (например,  с
                помощью функции OLON).

Ъ--------------------------------------------------------------Дї
і                   Пример обращения к OROL                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і                         orol(lda);                            і
А--------------------------------------------------------------ДЩ




ФУНКЦИЯ OCON
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                        CALL OCON (lda)                        і
А--------------------------------------------------------------ДЩ

Функция OCON  включает  режим  автоматического   подтверждения
транзакций (автоматического подтверждения изменений, внесенных
в базу любым оператором манипулирования данных SQL).  По-умол-
чанию, в начале работы с интерфейсом ORACLE (OCI), режим авто-
матического подтверждения транзакций отключен,  поскольку  его
использование дороже и менее гибко,  чем вызов OCOM после каж-
дого логического участка работы (логической транзакции).  Если
режим  автоматического  подтверждения  транзакций включен,  то
всякий раз,  когда OEXEC завершается успешно, внесенные в базу
изменения  становятся постоянными (транзакция подтверждается).
Однако,  может возникнуть ситуация, когда это удобно, и Вы мо-
жете  включить режим автоматического подтверждения транзакций,
обратившись к подпрограмме OCOM.  Если функция  OCOM  аварийно

завершается, то в первые два байта области данных связи (LDA -
logon data area) помещается код,  по которому можно определить
причину аварийного завершения OCOM.

lda (адрес)   - адрес области  LDA,  которая  была  связана  с
                ORACLE  при подсоединении к нему (например,  с
                помощью функции OLON).

Не путайте  функцию  OCOM (COMMIT WORK - подтвердить внесенные
изменения) с функцией OCON (то же самое, что SET AUTOCOMMIT ON
- установить режим автоматического подтверждения транзакций).

Ъ--------------------------------------------------------------Дї
і                   Пример обращения к OCON                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і                         ocon(lda);                            і
А--------------------------------------------------------------ДЩ



ФУНКЦИЯ OCOF
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                        CALL OCOF (lda)                        і
А--------------------------------------------------------------ДЩ

Функция OCOF  отключает  режим  автоматического  подтверждения
транзакций (автоматического подтверждения изменений, внесенных
в базу любым оператором манипулирования данных SQL).  По-умол-
чанию,  в начале работы программы Pro*SQL, этот режим уже отк-
лючен. Если при каких-то особенных обстоятельствах Вы восполь-
зовались функцией OCON,  то Вы можете вызвать OCOF, как только
исчезнет  потребность  в  режиме автоматического подтверждения
транзакций.  Если функция OCOF аварийно завершается, то в пер-
вые два байта области данных связи (LDA - logon data area) по-
мещается код,  по которому можно определить причину аварийного
завершения OCOF.

lda (адрес) - адрес области LDA, которая была связана с ORACLE
         при подсоединении к нему (например, с помощью функции
         OLON).

Ъ--------------------------------------------------------------Дї
і                   Пример обращения к OCOF                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і                       if (ocof(lda));                         і
А--------------------------------------------------------------ДЩ

.


                            - 156 -



ФУНКЦИЯ OERMSG
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                  CALL OERMSG (rcode, msgbuf)                  і
А--------------------------------------------------------------ДЩ

Функция OERMSG помещает в указанный буфер сообщение об  ошибке
ORACLE,  соответствующее указанному коду завершения. Если ука-
занному коду никакое сообщение не соответствует,  то  в  буфер
помещается сообщение "Unknown ORACLE error code" ("Неизвестный
код ошибки ORACLE").

rcode (двоичное целое число) - код завершения,  которому будет
            соответствовать   возвращаемое  сообщение.  OERMSG
            ищет коды ошибок V2/V3,  однако код V4 с  обратным
            знаком  тоже  сработает (что такое коды V2/V3 и V4
            см. в обсуждении кодов ошибок в главе 8).

msgbuf (адрес) - адрес буфера,  в который будет помещен  текст
            сообщения, заканчивающийся нулевым символом. Длина
            этого текста не может превышать 132 символа.  Если
            текст  сообщения  не помещается в буфер,  то часть
            его будет отсечена.

Ъ--------------------------------------------------------------Дї
і                   Пример обращения к OERMSG                   і
Г--------------------------------------------------------------Дґ
і                                                               і
і                      oermsg(cur[0],msg);                      і
А--------------------------------------------------------------ДЩ




ФУНКЦИЯ OCMN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                CALL OCMN (lda,comment-,commentl-)             і
А--------------------------------------------------------------ДЩ

Функция OCMN не поддерживается.

.


                            - 157 -



ФУНКЦИЯ OCLOSE
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                     CALL OCLOSE (cursor)                      і
А--------------------------------------------------------------ДЩ

Функция OCLOSE отсоединяет курсор от ORACLE (закрывает курсор)
и освобождает все ресурсы выделенные при обращениях  к  OOPEN,
OSQL и OEXEC с этим курсором.  Если при выполнении OCLOSE воз-
никла ошибка,  код завершения этой подпрограммы  помещается  в
поле  кода завершения в области данных курсора.  Коды заверше-
ния,  соответствующие возникшим ошибкам  перечислены  в  книге
"Сообщения об Ошибках ORACLE и их Коды" (ORACLE Error Messages
and Codes Manual).

Ъ--------------------------------------------------------------Дї
і                   Пример обращения к OCLOSE                   і
Г--------------------------------------------------------------Дґ
і                                                               і
і                         oclose(curs);                         і
А--------------------------------------------------------------ДЩ




ФУНКЦИЯ OLOGOF
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і                       CALL OLOGOF (lda)                       і
А--------------------------------------------------------------ДЩ

Функция OLOGOF  отсоединяет  программу от ORACLE и освобождает
все ресурсы ORACLE, принадлежащие данной программе.

При успешном  завершении  подпрограммы  OLOGOF   автоматически
подтверждаются  еще не подтвержденные транзакции.  Кроме того,
все неазкрытые курсоры закрываются во время OLOGOF. Если прог-
рамма  пользователя не отсоединится успешно от ORACLE или ава-
рийно завершится, то все не подтвержденные транзакции анулиру-
ются.  Если  функция OLOGOF аварийно завершается,  то в первые
два байта области данных связи (LDA - logon data area) помеща-
ется код,  по которому можно определить причину аварийного за-
вершения OLOGOF.  Коды завершения,  соответствующие  возникшим
ошибкам  перечислены в книге "Сообщения об Ошибках ORACLE и их
Коды" (ORACLE Error Mes- sages and Codes Manual).

lda (адрес) - адрес области LDA, которая была связана с ORACLE
         при подсоединении к нему (например, с помощью функции
         OLON).

Ъ--------------------------------------------------------------Дї
і                   Пример обращения к OLOGOF                   і
Г--------------------------------------------------------------Дґ
і                                                               і
і                         ologof(lda);                          і
А--------------------------------------------------------------ДЩ

.


                            - 158 -







ГЛАВА 10. ТИПЫ ДАННЫХ
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН

В этой главе обсуждаются типы данных, используемые программами
OCI и СУБД ORACLE, а также возможные их преобразования.

ORACLE осуществляет  преобразования  почти  всех типов данных,
имеющихся в поддерживаемых им языках программирования.  Выпол-
няя  операции  выбора  (SELECT),  ORACLE преобразует данные из
внутреннего формата,  в котором они хранятся в базе,  во внеш-
ний,  определенный программой пользователя.  Выполняя операции
занесения в базу (INSERT и UPDATE),  ORACLE преобразует данные
из внешних форматов (типов) во внутренние.

Внешний тип данных для операций SELECT пользователь определяет
с помощью подпрограммы ODEFIN.  Внешние типы данных для опера-
ций  IN- SERT и UPDATE пользователь определяет с помощью подп-
рограмм OBNDRV и OBNDRN.

Внутри ORACLE символьные данные хранятся в формате  ASCII  или
EBCDIC,  а числовые в формате целых масштабированных чисел пе-
ременной длины. Даты (данные типа DATE) хранятся внутри ORACLE
в семи байтах в виде ГГГГММ--ЧЧММСС.

Если пользователь не хочет, чтобы ORACLE преобразовывал число-
вые данные, их можно определить как символьные для внутреннего
и внешнего представлений.


ОПИСАНИЯ ТИПОВ ДАННЫХ
----------------------------------------------------------------

На рисунке  17  на странице 203 приведены внешние типы данных,
поддерживаемые ORACLE.

Ниже приведено описание внешних типов данных ORACLE:

01   Данные в  формате  символьной цепочки (строки) переменной
     длины представляют собой строку символов,  закодированных
     кодом  ASCII или EBCDI,  длина которой определяется полем
     длины.  При вводе концевые пробелы отбрасываются. При вы-
     воде  ORACLE  дополняет  строки до нужной длины концевыми
     пробелами.

     Если при вводе длина цепочки символов не указана,  то она
     определяется сканированием строки  до  тех  пор  пока  не
     встретится нулевой символ (код которого 0).  Нулевой сим-
     вол ищется только среди первых 240 символов строки.  Если
     он не будет найден, то длина строки будет равна 240.
.


                            - 159 -


Ъ------------------ДВ------ДВ------------В--------------В------ї
і    ТИП ДАННЫХ     і  КОД  і  ФОРТРАН   і   КОБОЛ      і  СИ  і
ЖНННННННННННННННННННШНННННННШННННННННННННШННННННННННННННШННННННµ
і Символьная строка і  01   і LOGICAL*1  і  PIC X...X   і CHAR і
і переменной длины  і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і Числовые данные воі  02   і    N/A     і    N/A       і N/A  і
і внутреннем форматеі       і            і              і      і
і ORACLE            і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і 8-битовые с фикси-і  03   і  LOGICAL*1 і    N/A       і CHAR і
і рованной точкой   і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і 16-битовые с фик- і  03   і  INTEGER*2 іPIC S9(4) COMPі SHORTі
і сированной точкой і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і 32-битовые с фик- і  03   і  INTEGER*4 іPIC S9(9) COMPі LONG і
і сированной точкой і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і 32-битовые с пла- і  04   і  REAL*4    і    N/A       і FLOATі
і вающей точкой     і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і 64-битовые с пла- і  04   і  REAL*8    і    N/A       іDOUBLEі
і вающей точкой     і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і Символьные строки,і  05   і  LOGICAL*1 і  PIC X...X   і CHAR і
і ограниченные нуле-і       і            і              і      і
і вым символом      і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і Необработанные    і  06   і  LOGICAL*1 і  PIC X...X   і CHAR і
і (сырые) данные    і       і            і              і      і
і (Raw data)        і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і Упакованные деся- і  07   і    N/A     і  PIC S9V9    і N/A  і
і тичные КОБОЛа     і       і            і  COMP3       і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і Данные типа LONG  і  08   і    N/A     і     N/A      і N/A  і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і Данные неизвестно-і  10   і    N/A     і     N/A      і N/A  і
і го (unknown) типа і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і ROWID             і  11   і    N/A     і     N/A      і N/A  і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
іВнутреннее представ-  12   і    N/A     і     N/A      і N/A  і
іление даты (DATE)  і       і            і              і      і
Г------------------ДЕ------ДЕ------------Е--------------Е------ґ
і Внутренняя юлианс-і  14   і    N/A     і     N/A      і N/A  і
і кая дата          і       і            і              і      і
А------------------ДБ------ДБ------------Б--------------Б------Щ

       Рис. 17.  Внешние типы данных, поддерживаемые ORACLE


     Если при вводе указана длина строки,  то нулевой символ в
     строке не ищется.  При  выводе  требуется  длина  строки.
     Пустое  поле или такое,  длина которого равна нулю ORACLE
     рассматривает как NULL (пустое данное). При выводе строка
     не  может иметь нулевую длину.  Если внутри ORACLE данные
     имеют тип NUMBER (числовые),  то входные цепочки символов
     преобразуются  во  внутренний  числовой формат до тех пор


                            - 160 -

     пока  не  встретится  не   числовой   символ.   Например,
     '1234.45bcd'  преобразуется в 1234.45,  а 'bcd' игнориру-
     ется;  при этом возвращается ошибка преобразования данных
     c  кодом +5.  Данные во внутреннем числовом формате можно
     выводить в символьный буфер в кодах ASCII. Допустим также
     ввод  числа во внутреннем формате из буфера,  содержащего
     его символьное представление в кодах  AS-  CII.  Точность
     при  выводе  определяется шириной поля.  Если ширина поля
     слишком мала,  число будет приведено к стандартному  виду
     (с мантиссой и порядком).  Например, если выводится число
     123456789,  а ширина поля 6,  то выходной  строкой  будет
     '1.2E08'.


02   Ниже приведен общий формат числа в ORACLE:

 і  байт 0  і   байт 1   і   байт 2  і   байт 3  і
 Г----------ЕДВ----------Е----------ДЕ----------ДЕ------Д
 і          ібі          і           і           і
 і          іиі          і           і           і
 і          іті          і           і           і
 і          і і          і           і           і
 і  Длина   ізі порядок  і   цифра   і   цифра   і  . . .
 і          іні          і           і           і
 і          іаі          і           і           і
 і          ікі          і           і           і
 і          іаі          і           і           і
 А----------БДБ----------Б----------ДБ----------ДБ--------
                         ^
                         і
           подразумеваемая десятичная точка

     Д л и н а - это длина числа;  она равна количеству цифр в
     нем плюс один.  В некоторых интерфейсах длина может отде-
     ляться и передаваться как отдельный параметр. Минимальное
     значение,  которое может принимать длина, равно минималь-
     ному размеру числа в ORACLE,  а максимальное - максималь-
     ному.  В настоящее  время  максимальный  размер  числа  в
     ORACLE - 22 байта.

     Б и т   з н а к а - это старший бит байта порядка.  Если
     этот бит выставлен,  число положительно,  если сброшен  -
     отрицательно.

     П о р я д о к  - это 7 младших битов байта порядка.  Поря-
     док принимает значения от 0 до 127 и хранится в виде сум-
     мы с числом 64. То есть результат вычитания 64 из порядка
     определяет на сколько байт сдвинуть число.  Если этот ре-
     зультат отрицательный, то число сдвигается вправо от под-
     разумеваемой десятичной точки,  а если он  положительный,
     то влево.

     Каждая   ц и ф р а   есть двоичное число от 0 до 99,  она
     представляет одну из 100 основных цифр.  К  каждой  цифре
     прибавлена 1, чтобы двоичный 0 не соответствовал никакому
     числу. (Проблемы с двоичным нулем возникли бы если бы по-
     ле было индексированное (indexed)).  Таким образом каждая
     цифра во внутреннем представлении является числом от 1 до
     100.  Первая цифра всегда ненулевая,  поскольку все числа
     приведены к стандартному  виду  (нормализованы).  Отрица-
     тельные  числа есть преобразованные положительные.  Соот-


                            - 161 -

     ветствующее преобразование  делается  следующим  образом:
     отрицательный байт порядка включая бит знака,  есть поло-
     жительный байт порядка,  записанный в дополнительном коде
     (все единицы меняются на нули и наоборот). Каждая отрица-
     тельная цифра есть дополнение до 100  соответствующей  ей
     положительной  цифры плюс один.  Это означает,  что соот-
     ветствующая отрицательная цифра получается вычитанием по-
     ложительной из 100.  Если отрицательное число содержит не
     максимальное количество цифр,  то в конец его добавляется
     102.  Такое  преобразование положительных чисел в отрица-
     тельные гарантирует,  что  результат  сравнения  чисел  в
     ORACLE всегда будет правильным.

     Ноль представляется однобайтовым числом,  содержащим 128.
     Это байт порядка с выставленным битом знака и  минимально
     возможным порядком. Это гарантирует, что ноль будет мень-
     ше всех положительных и больше всех отрицательных чисел.

     Положительная бесконечность представляется двумя  байтами
     (255,101),   а   отрицательная   бесконечность   -  тремя
     (1,1,102).  Такие их представления  были  выбраны,  чтобы
     сравнения  с обеими бесконечностями давали правильный ре-
     зультат.

03   Целочисленный формат используется для обработки чисел без
     дробной части.  Целое число - это двоичное число со  зна-
     ком,  занимающее  один,  два  или четыре байта.  Их стар-
     шинство определяется используемым  языком  программирова-
     ния.  При вводе и выводе необходимо указывать длину. Если
     выводимое из ORACLE число не целое дробная часть отбрасы-
     вается. Целые числа можно использовать только со столбца-
     ми внутрен-него числового типа.

04   Формат с  плавающей  точкой  используется  для  обработки
     чисел  с дробными частями или чисел превышающих (по моду-
     лю)  максимально  допустимое  целое  число.  Такие  числа
     представляются  так  же,  как представляются в компьютере
     обычные числа с плавающей точкой длины  4  или  8  байтов
     (REAL*4 или FOLAT, REAL*8 или DOUBLE). При вводе и выводе
     необходимо указывать длину. Поскольку внутренний числовой
     формат  основан на десятичном представлении,  может иметь
     место  некоторая  потеря  точности  при   преобразованиях
     компьютерного формата чисел с плавающей точкой в десятич-
     ный формат ORACLE и обратно.

05   Формат строк,  ограниченных нулевым символом такой же как
     формат символьных строк переменной длины,  за исключением
     того,  что строки всегда заканчиваются байтом, содержащим
     ноль  (нулевым символом).  При вводе можно указать макси-
     мальную длину строки,  которая будет использована для ог-
     раничения поиска нулевого символа. Если нулевой символ не
     был найден,  то длина строки будет равна указанной макси-
     мальной длине.  Если максимальная длина строки не указана
     она принимается равной 240 символам.  При  выводе,  после
     последнего  символа  строки  добавляется  нулевой символ.
     Если строка выходит за пределы соответствующего поля,  то
     часть ее отсекается и в последней позиции буфера,  содер-
     жащего строку,  ставится нулевой символ.  Строки  нулевой
     длины  (нулевой символ в первой позиции либо все поле за-
     полнено пробелами) ORACLE расматривает как  NULL  (пустое
     данное).


                            - 162 -

06   Формат "сырых"  данных (raw data) используется для двоич-
     ных данных. ORACLE никак не интерпретирует содержимое бу-
     фера ни при вводе ни при выводе. При вводе и выводе необ-
     ходимо указывать  длину.  При  выводе  возвращается  лишь
     столько символов, сколько хранится в базе; остаток буфера
     вывода  остается  без  изменений.  Количество  фактически
     возвращенных  символов  можно  определить,  обратившись к
     подпрограмме ODSC.

07   Десятичный упакованный тип  данных  КОБОЛа  используется,
     чтобы  возвратить из ORACLE не целые числа в формат КОБО-
     ЛА,  пригодный для  вычислений.  Областью  данных  КОБОЛа
     должно быть поле COMP3 (упакованное) со знаком с подразу-
     меваемой (фиксированной (implied)) десятичной точкой. Ко-
     личество  цифр  справа  от десятичной точки можно опреде-
     лить,  обратившись к подпрограмме ODEFIN. Более подробную
     информацию  об  определении  преобразования формата можно
     почерпнуть в описании ODEFIN. Возвращаемое значение можно
     использовать  для  вычислений  в КОБОЛе непосредственно в
     том виде,  в котором оно возвращается, либо можно предва-
     рительно    поместить    его    в   вычислительное   поле
     (computational field). К стандартному виду (с мантиссой и
     порядком)  число  не приводится.  Если возвращаемое число
     теряет значимые цифры при преобразовании формата,  ORACLE
     заполняет буфер символами "*".

08   Тип данных  LONG (длинный) используется в ORACLE для хра-
     нения строк данных, длина которых превышает 240 символов.
     Он  применяется только для занесения и извлечения длинных
     строк и не может быть использован в функциях,  выражениях
     или в предложениях WHERE. Обычно, данные этого типа возв-
     ращаются в символьные строки.

10   Когда ODSC используется для определения  типа  некоторого
     элемента  списка выбора (select-list),  могут встретиться
     некоторые  выражения,  содержащие  заменяемые  переменные
     (substitution variables),  тип которых нельзя определить,
     пока переменным не будут присвоены какие-нибудь значения.
     Так  если из величины типа DATE (дата)вычитается заменяе-
     мая переменная, то в результате получится число юлианских
     дней  (тип 14),  если переменная тоже имеет тип DATE,  но
     если переменная - число,  то результат будет  типа  DATE.
     Фактический  тип этого поля можно определить только после
     того как переменной будет присвоено  какое-нибудь  значе-
     ние.

11   Данное типа ROWID (идентификатор строки) представляет со-
     бой внутренний указатель ORACLE на физический адрес стро-
     ки  таблицы  в  базе данных.  Обычно,  данные такого типа
     используются в операторах SELECT FOR UPDATE. Подробнее об
     использвании ROWID см.  в Руководстве Администратора Базы
     Данных ORACLE (ORACLE Database Administrator's Guide).

12   Внутреннее представление даты в  ORACLE  (DATE)  содержит
     дату в семибайтовом поле, в котором хранятся справа нале-
     во: год (два байта), месяц, день, часы, минуты и секунды.
     Даты,  обычно,  надо  возвращать  из  ORACLE в символьную
     строку  переменной  длины  (тип  01),  используя  функцию
     TO_CHAR в списке выбора (select-list) оператора SQL.
.


                            - 163 -

14   Внутреннее юлианское  представление  даты  есть результат
     выражения,  в котором одна величина типа DATE  вычитается
     из другой величины типа DATE.  Это число дней между двумя
     датами.




ПРЕОБРАЗОВАНИЯ ДАННЫХ
----------------------------------------------------------------

На рисунке 18 показаны поддерживаемые ORACLE преобразования
данных.

        Ъ--------------------------ДВ------------ДВ------------Дї
        і СИСТЕМНЫЙ ФОРМАТ          і   В ORACLE  і  ИЗ ORACLE  і
        Г--------------------------ДЕ------В------Е------В------ґ
        і ПОЛЬЗОВАТЕЛЬСКИЙ ФОРМАТ   і СИМВ і ЧИСЛ і СИМВ і ЧИСЛ і
        ЖНННННННННННННННННННННННННННШННННННШННННННШННННННШННННННµ
        і ASCII/EBCDI               і  ДА  і  ДА  і  ДА  і  ДА  і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і Внутренний числовой       і  ДА  і  ДА  і  ДА  і  ДА  і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і 8-битовый с фикс. точкой  і      і  ДА  і   -  і  ДА  і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і 16-битовый с фикс. точкой і      і  ДА  і   -  і  ДА  і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і 32-битовый с фикс. точкой і      і  ДА  і   -  і  ДА  і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і 32-битовый с плав. точкой і      і  ДА  і   -  і  ДА  і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і 64-битовый с плав. точкой і      і  ДА  і   -  і  ДА  і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і Симв. строка ограниченная і  ДА  і  ДА  і  ДА  і  ДА  і
        і                           і      і      і      і      і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і "Сырые" данные (RAW DATA) і  ДА  і  ДА  і  ДА  і  ДА  і
        Г--------------------------ДЕ------Е------Е------Е------ґ
        і Упакованные КОБОЛа        і НЕТ  і НЕТ  і НЕТ  і  ДА *і
        А--------------------------ДБ------Б------Б------Б------Щ

             Рис. 18.   Таблица Преобразований Данных

ПРИМЕЧАНИЕ: 'Числовой'  тип  данных  КОБОЛА должен быть описан
следующим образом:

        PICTURE S9(N)V9(N) USAGE COMP3.

.


                            - 164 -



Глава 11. Старые Функции Pro*SQL (OCI)




ОПИСАНИЯ ОБРАЩЕНИЙ К
ФУНКЦИЯМ OCI
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН

В этой  главе  описываются  обращения к более старым функциям,
которые были заменены функциями, описанными в Главе 2, но при-
водятся здесь для полноты.

Каждой функции посвящен раздел, в котором описан синтаксис
обращения к ней,  расказано как ее использовать и что означают
ее  параметры,  а  также приведены примеры обращений из языков
ФОРТРАН,  КОБОЛ и СИ.  Описания вызовов подпрограмм следуют не
по  алфавиту,  а примерно в том порядке,  в котором они должны
появляться в программе.  (В алфавитном поядке эти функции пее-
числены в приложении G.)

Функции, описанные  в  этой  главе,  были  заменены функциями,
описанными в предыдущей главе.  Приведенные здесь функции под-
держиваются в соответствии с данными описаниями,  однако у них
меньше функциональных возможностей,  чем у новых функций. Поэ-
тому в новых программах рекомендуется использовать новые функ-
ции.  О старых функциях здесь рассказывается для  того,  чтобы
программисты могли понять программы, написанные с их использо-
ванием.

Слова "функция" и "подпрограмма"  будем  использовать  в  этой
главе как синомы.
.


                            - 165 -


*           OLOGON    Организовать область связи (Logon Data
              |       Area)
              V
            OOPEN     Открыть область данных курсора (Cursor
              |       Data Area)
              V
*           OSQL      Связать оператор SQL с курсором и про-
              |       вести его синтаксический разбор
              V
*           ODFINN    Определить программные буферы, в которые
              |       будут заноситься элементы списка выбора
              |       (К ODFINN надо обратиться по разу для
              |       каждого элемента списка.)
              V
*  -------->OBIND     Передать в ORACLE значения переменных
   |         или      программы, используемых в операторе SQL
*  |        OBINDN
   |          |
   |          V
   |        OEXE      Выполнить текущий оператор SQL, связан-
   |          |       ный с указываемым курсором
   |          V
   |   ---->OFETCH    Извлечь в программный(ые) буфер(ы),
   |   |      |       определенный(ые) в обращении к ODFINN,
   |   |      |       строку, выбранную из таблиц(ы) ORACLE
   |   | нет  V
   |   ------EOF?     Если не выставлен признак конца извлече-
   |          |       ния, то:
   |          |          извлечь следующую строку
   |       да |       Если все строки извлечены, то:
   |          |          Если надо выполнить еще один опера-
   |          |          тор SQL, то:
   |          |             перейти к вызову функции OSQL
   -----------|          Если надо подставить в тот же опера-
              |          тор SQL другую переменную программы,
              |          то:
              |             сменить переменную программы
              |             перейти к вызову OBIND или OBINDN
              V
            OCLOSE    Иначе закрыть курсор.
              V
            OLOGOF    Отсоединиться от ORACLE

Рис. 16.   Структура программы, реализующей запросы в версии 1
           и версии 2 Pro*SQL(OCI)




ФУНКЦИЯ OLOGON
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і               CALL OLOGON (lda [,areacount])                  і
А--------------------------------------------------------------ДЩ
Функция OLOGON использовалась в версии 2 ORACLE,  для установ-
ления связи между ORACLE и программой пользователя. OLOGON бы-
ла заменена новой функцией OLON.
.


                            - 166 -

Связь осуществляется  через специальную область данных связи -
LDA (logon data  area),  выделяемую  программой  пользователя.
Функция OLOGON связывает LDA и ORACLE. Программа может подсое-
диниться к ORACLE один и только один раз.  У  программы  может
быть  одна  и только одна LDA.  Если после обращения к функции
OLOGON,  осуществляется отсоединение от ORACLE, то все неподт-
вержденные еще транзакции подтверждаются. Если программа поль-
зователя не отсоединится успешно от ORACLE или аварийно завер-
шится, то все не подтвержденные транзакции анулируются.

Обратите внимание,  что функция OLOGON присутствует только для
совместимости с версией 2 и при обращении к  ней  фактического
подсоединения к ORACLE не происходит.  Фактическое подсоедине-
ние осуществляется при вызове функции OOPEN.  Если между обра-
щениями  к OLOGON и OLOGOF не было обращения к OOPEN,  то воз-
никнет ошибка "not logged on" ("нет подсоединения").

LDA - это область данных размером в 64 байта,  определенная  в
программе  пользователя.  Число в формате short binary integer
(короткое двоичное целое) в начале этой области  содержит  код
завершения, показывающий чем кончилось обращение к OLOGON. Ну-
левой код завершения означает что подсоединение к ORACLE прош-
ло нормально. Коды завершения, соответствующие возникшим ошиб-
кам перечислены в книге "Сообщения об Ошибках ORACLE и их  Ко-
ды" (ORACLE Error Messages and Codes Manual).

lda (адрес) - адрес 64-байтовой области связи, определенной в
         программе пользователя.

areacount (двоичное целое число) присутствует только для
         совместимости с версией 2 ORACLE. Не используется.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OLOGON                    і
Г--------------------------------------------------------------Дґ
і                                                               і
і                       olon(ldarea,2);                         і
А--------------------------------------------------------------ДЩ




ФУНКЦИЯ OSQL
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і         CALL OSQL ( cursor, sqlstatement [,sqlen] )           і
А--------------------------------------------------------------ДЩ

Функция OSQL связывает оператор SQL с открытым курсором и  пе-
редает  этот  оператор  в  ORACLE для обработки.  Функция OSQL
используется только для поддержки синтаксиса ORACLE версии  2.
Она была заменена новой функцией OSQL3.  Обе эти функции можно
использовать в одной программе,  однак  редактирование  связей
должно осуществляться по-другому для программ,  содержащих об-
ращения к OSQL.

Все прочие функции для обозначения  оператора  SQL  используют
имя соответствующего курсора.
.


                            - 167 -

Один и  тот же курсор может последовательно встречаться в раз-
ных обращениях к OSQL.  Программа пользователя может также оп-
ределить несколько курсоров параллельно.

Коды синтаксических  ошибок  SQL возвращаются (в виде кода за-
вершения в области данных курсора) и указателя (в виде  смеще-
ния  от начала текста оператора) на то место в тексте операто-
ра,  где возникла ошибка. Возможные синтаксические ошибки при-
ведены  в  главе "Синтаксические Ошибки" в книге "Сообщения об
Ошибках ORACLE и их  Коды"  ("Parse  Errors"  в  ORACLE  Error
Messages and Codes Manual).

cursor (адрес)  - адрес 64-байтовой области данных в программе
         пользователя.  Область данных курсора содержит инфор-
         мацию  о  состоянии  активной  операции  SQL.  Каждый
         курсор определяет в программе  пользователя  открытый
         оператор SQL.

sqlstatement (адрес) - адрес символьной строки, содержащей не-
         который допустимый оператор SQL.  В любом месте этого
         оператора,  где  допускаются константы,  могут стоять
         заменяемые переменные (substitution variables). Заме-
         няемые  переменные обозначаются двоеточием перед име-
         нем переменной,  например,  :EMPNO. Впоследствие, при
         вызове функций OBIND, OBINDN, OBNDRN или OBNDRV, мож-
         но указывать заменяемые переменные пользуясь их  име-
         нами.

sqllen (двоичное целое число) - длина оператора SQL. Если сим-
         вольная строка,  содержащая оператор оканчивается ну-
         левым символом, то этот параметр можно опустить.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к OSQL                      і
Г--------------------------------------------------------------Дґ
і                                                               і
і       osql (curs,"SELECT NVL(MAX(EMPNO) FROM EMP"),-1);       і
А--------------------------------------------------------------ДЩ





ФУНКЦИЯ ODSRBN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і       CALL ODSRBN (cursor,position [,dbsize] [,fsize])        і
А--------------------------------------------------------------ДЩ

Функция ODSRBN  возвращает информацию о внутреннем типе данных
и размере поля или выражения  в  списке  выбора  (select-list)
запроса SQL.

Поле для  ODSRBN  (при  каждом  обращении эта функция работает
только с одним полем) идентифицируется  номером  (позицией)  в
списке  выбора оператора SELECT.  При этом считается,  что все
поля занумерованы в списке выбора последовательно,  слева нап-
раво, начиная с единицы.
.


                            - 168 -

Использовать ODSC  можно  после  обращений  к OSQL,  OEXEC или
OFETCH, чтобы определить максимальные размеры, внутренние типы
данных (dbsize и dbtype) полей,  возвращаемых в результате вы-
полнения запроса.  Если ODSRBN используется после OFETCH,  то,
кроме  dbsize  и dbtype,  может также возвращаться фактический
размер (fsize) только что извлеченного (fetched) поля.

Если указанный пользователем номер позиции превышает количест-
во полей в списке выбора,  то в поле кода завершения в области
данных курсора  ODSRBN  возвращает  признак  конца  извлечения
(end-of-fetch indicator). Это позволяет программам динамически
определить сколько полей должно быть возвращено  в  результате
выполнения запроса. Это необходимо, если программе заранее не-
известно количество полей в списке выбора,  как,  например,  в
случае SELECT *.

cursor (адрес)  - адрес 64-байтовой области данных в программе
         пользователя.  Область данных курсора содержит инфор-
         мацию об активной операции SQL. Каждый курсор опреде-
         ляет в программе пользователя активный оператор  SQL.
         Имя курсора используется для указания ODSRBN операто-
         ра SQL,  переданного ранее в ORACLE с помощью функции
         OSQL.  Поле  кода завершения в области данных курсора
         показывает успешное (нулевое значение) или  ошибочное
         (ненулевое  значение) завершение подпрограммы ODSRBN.
         Коды завершения,  соответствующие  возникшим  ошибкам
         перечислены в книге "Сообщения об Ошибках ORACLE и их
         Коды" (ORACLE Error Messages and Codes Manual).

position (двоичное целое число) - позиция поля или выражения в
         списке выбора запроса SQL.  Поля и выражения в списке
         выбора разделяются запятыми.  Каждое поле или выраже-
         ние  обозначается  номером позиции,  получающимся при
         последовательной их нумерации слева направо,  начиная
         с единицы. Если указанный пользователем номер позиции
         превышает количество полей в списке выбора,  то  ODSC
         возвращает признак конца извлечения (end-of-fetch in-
         dicator) в поле  кода  завершения  в  области  данных
         курсора.

dbsize (адрес)  -  адрес переменной тиапа short binary integer
         (короткое двоичное целое),  которая примет  значение,
         равное максимальному размеру поля,  в соответствии со
         Словарем Данных (Data Dictionary).  Если поле опреде-
         лено, как CHAR или NUMBER, то возвращаемая длина рав-
         на максимальной длине, указанной для этого поля.

dbtype (адрес) - адрес переменной типа short binary integer, в
         которую  будет помещен внутренний тип данных поля,  в
         соответствии со словарем  данных  (Data  Dictionary).
         Поля, определенные как CHAR, хранятся в виде символь-
         ных строк переменной длины  и  для  них  возвращаемое
         значение равно 1. Поля, определенные как NUMBER, хра-
         нятся во внутреннем  формате  масштабированных  целых
         чисел ORACLE и для них возвращаемое значение равно 2.
         Для полей, содержащих результаты выражений, возвраща-
         емое значение также равно 2.  Поля,  определенные как
         DATE,  хранятся в виде ГГГГММ--ЧЧММСС и для них возв-
         ращаемое значение равно 12.
.


                            - 169 -

fsize (адрес) Этот параметр имеет смысл только если ODSC вызы-
         вается после OFETCH.  Он указывает  адрес  переменной
         типа  short binary integer,  в которую будет помещена
         фактическая длина хранящегося в базе данных значения,
         извлеченного   при   последнем  обращении  к  функции
         OFETCH.  Возвращаемая фактическая длина хранящегося в
         базе  данных  значения  есть его длина до помещения в
         буфер пользователя,  т.к.  при помещении его в  буфер
         могло  иметь  место  отсечение непомещающейся в буфер
         части этого значения или,  наоборот,  дополнение  его
         концевыми  пробелами.  Перед  записью значений в базу
         данных ORACLE отбрасывает нули в начале числовых дан-
         ных и концевые пробелы в символьных.

Ъ--------------------------------------------------------------Дї
і                 Пример обращения к ODSRBN                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і        odsrbn(curs[1],1,&ename,(short *)1,(short *)-1);       і
А--------------------------------------------------------------ДЩ




ФУНКЦИЯ ODFINN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і CALL ODFINN (cursor, pos, buffer, bufl[,ftype][,rcode][,fdig])і
А--------------------------------------------------------------ДЩ

Функция ODFINN определяет выходные буферы, соответствующие по-
лям  в  списке  выбора запроса SQL (каждому полю соответствует
один буфер).  Функция  ODFINN  была  заменена  новой  функцией
ODEFIN.

С помощью  ODFINN  указывается  местоположение и размер буфера
поля данных в программе пользователя.  ODFINN также  позволяет
указать внешний тип данных поля, определяемый программой поль-
зователя и (если пользователь этого хочет) определить перемен-
ную, в которую будет помещаться код завершения на уровне поля.
При каждом обращении к ODFINN определяется один буфер.  Буферы
должны определятся после обращения к OSQL, но перед обращением
к OFETCH.

Буферы выбора всегда определяются позиционно.  Поля  в  списке
выбора,  обозначаются номером позиции в списке, причем зануме-
рованы они последовательно слева направо,  начиная с  единицы.
При  выполнении  функции OFETCH ORACLE преобразует каждое поле
из внутреннего типа данных в указанный внешний тип, после чего
заносит значения полей в соответствующие им буферы (определен-
ные с помощью ODEFIN).

ORACLE возвращает через область данных курсора код  завершения
на  уровне  строки  таблицы и дополнительно,  т.е.  по желанию
пользователя, кода завершения на уровне отдельного поля, через
указанную  при  вызове  ODFINN  переменную.  При каждом вызове
OFETCH ORACLE устанавливает код завершения для каждого обрабо-
танного поля. Это код показывает было ли поле извлечено успеш-
но (0) или возникла какая-то исключительная  ситуация,  напри-
мер,  было извлечено пустое поле, часть поля была отсечена или


                            - 170 -

возникла еще какая-нибудь не критическая ошибка при работе  со
столбцом.  Коды завершения на уровне отдельных полей заносятся
в переменные rcode для каждого поля, для которого эта перемен-
ная определена.  По завершении OFETCH, последний ненулевой код
завершения на уровне поля заносится в поле кода завершения,  в
области данных курсора.

cursor (адрес)  - адрес 64-байтовой области данных в программе
         пользователя. Функция ODFINN пользуется именем курсо-
         ра,  чтобы  связать  буфер поля данных с определенным
         оператором SQL.

pos (двоичное целое число) - номер позиции поля или  выражения
         в списке выбора запроса SQL.  Поля списке выбора раз-
         деляются запятыми и нумеруются последовательно  слева
         направо,  начиная с единицы. Если указанный пользова-
         телем номер  позиции  превышает  количество  полей  в
         списке  выбора,  то  в поле кода завершения в области
         данных курсора ODEFIN возвращает признак конца  файла
         (end-of-  fetch  indicator).  ODEFIN использует номер
         позиции, чтобы соотнести буферы с полями в списке вы-
         бора.

buffer (адрес) - адрес буфера поля данных в программе пользова-
         теля, в который будут помещены данные при обращении к
         OFETCH.

bufl (двоичное целое число) - длина определяемого буфера.

ftype (двоичное целое число) - внешний тип данных,  к которому
         будет преобразовываться поле перед помещением в буфер
         пользователя.  Список внешних типов данных приведен в
         главе 11.

rcode (адрес) - адрес переменной типа short binary integer , в
         которую  будет помещаться код завершения после выпол-
         нения подпрограммы OFETCH.

fdig (двоичное целое число) - количество цифр справа от  деся-
         тичной точки,  которое надо возвращать для полей типа
         7 (упакованные десятичные числа КОБОЛа).  fdig требу-
         ется для данных типа 7 и игнорируется для всех других
         типов данных.

Ъ--------------------------------------------------------------Дї
і                  Пример обращения к ODFINN                    і
Г--------------------------------------------------------------Дґ
і                                                               і
і           odfinn(curs,1,&empno,2,3,(short *)1,-1);            і
А--------------------------------------------------------------ДЩ




ФУНКЦИИ OBIND И OBINDN
----------------------------------------------------------------

Ъ--------------------------------------------------------------Дї
і   CALL OBIND (cursor,sqlvar,[sqlvl],progvar,[progvl],ftype)   і
і   CALL OBNIDN (cursor,sqlvarnum,progvar,[progvl],ftype)       і
А--------------------------------------------------------------ДЩ


                            - 171 -

Функции OBIND и OBINDN используются для динамического  измене-
ния  оператора  SQL  после  того,  как он был передан в ORACLE
функцией OSQL. Оператор SQL может быть выполнен, затем изменен
с  помощью  функций OBIND и OBINDN и снова выполнен в желаемом
виде.
Функции OBIND и OBINDN были заменены новыми функциями OBNDRV и
OBNDRN.

Вызовы функций OBIND и OBINDN указывают, что некоторая величи-
на в программе должна быть поставлена в соответствие некоторой
заменяемой переменной в операторе SQL.  Функции OBIND и OBINDN
почти ничем не различаются,  за исключением  способа,  которым
они  идентифицируют  заменяемые  переменные  в  операторе SQL.
OBNDRN идентифицирует их по номерам.  OBNDRV - по именам.  Имя
связываемой переменной не должно совпадать ни с одним из заре-
зервированных слов ORACLE.

В процессе связывания ORACLE преобразует переменную  программы
из внешнего формата во внутренний, после чего помещает ее зна-
чение в оператор SQL.  OBIND и OBINDN вызываются после обраще-
ния к OSQL и до обращения к OEXEC.  Если одна и та же заменяе-
мая переменная встречается в списке выбора более одного  раза,
то одно обращение к OBIND или OBINDN свяжет все ее встречания.
Количество установленных связей возвращается в поле  указателя
на  синтаксическую ошибку (Parse Error Offset field) в области
данных курсора.

Код завершения процесса связывания возвращается  в  поле  кода
завершения  в  области  данных курсора.  Коды возможных ошибок
описаны в книге  "Сообщения  об  Ошибках  ORACLE  и  их  Коды"
(ORACLE Error Messages and Codes Manual). Если возникает ошиб-
ка преобразования символьных данных в числовые  (код  +5),  то
процесс  связывания  прерывается  с  кодом +5.  Если возникает
ошибка ORACLE,  код которой отрицателен (например,  -625 -  не
поддерживаемое преобразование), то процесс связывания прерыва-
ется и поле местоположения синтаксической ошибки (Parse  Error
Offset field) в оласти данных курсора будет указывать на номер
встречания имени переменной, где возникла ошибка. Если заменя-
емое имя не существует, то возвращается ошибка ORACLE -605.

cursor (адрес)  - адрес 64-байтовой области данных в программе
         пользователя.  Функции OBIND и OBINDN используют  имя
         курсора, для обозначения определенного оператора SQL.

sqlvar (адрес) - адрес символьной строки, содержащей имя заме-
         няемой переменной в операторе SQL.  В  операторе  SQL
         перед именем переменной стоит двоеточие, т.е., напри-
         мер: WHERE EMPNO = :EMPLOYEE. OBIND помещает значение
         переменной    программы   в   заменяемую   переменную
         :EMPLOYEE.

sqlvl (двоичное целое число) - длина символьной строки, на ко-
         торую  указывает  sqlvar.  Например,  длина :EMPLOYEE
         равна 9.  Если после имени  заменяемой  переменной  в
         строке  стоит нулевой символ,  то этот параметр можно
         опустить.

sqlvarnum (двоичное целое число) - номер заменяемой переменной
         в  том  операторе  SQL,  на который указывает курсор.
         Например, если sqlvarnum равен 2, он указывает на за-
         меняемую переменную SQL, определяемую как :2.


                            - 172 -

progvar (адрес)  - адрес переменной,  определленой в программе
         пользователя,  значение которой будет извлекаться при
         выполнении OEXEC.

progvl (двоичное  целое  число)  - длина переменной программы.
         Если этот параметр равен нулю,  значит  с  переменной
         программы связано пустое значение.

ftype (двоичное целое число) - тип данных переменной,  опреде-
         ленный в программе.  Прежде  чем  связать  переменную
         программы с оператором SQL,  ORACLE преобразует ее из
         внешнего формата во внутренний. Внешние типы данных и
         их коды приведены в главе 11.

Ъ--------------------------------------------------------------Дї
і               Пример обращения к OBIND и OBINDN               і
Г--------------------------------------------------------------Дґ
і                                                               і
і             obind (curs,":ENAME",-1,strings,-1,1);            і
і             obindn(curs2,1,&deptno,2,3);                      і
А--------------------------------------------------------------ДЩ


                            - 156 -



ПРИЛОЖЕНИЕ A. СООБЩЕНИЯ ОБ ОШИБКАХ PRO*C
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН

     PRO*C во время прекомпиляции выдает ошибку или диагности-
ческое сообщение и также, когда выполняется прекомпилированная
программа.

     Есть четыре класса сообщений об  ошибках  PRO*C,  которые
выдаются в формате:

   *****W***** error text

     Эти классы  ошибок  приведены в порядке возрастания стро-
гости:

     W    Такие сообщения являются предостережениями, которые,
возможно,  проигнорирует по ошибке оператор SQL и создаст год-
ный к компиляции выходной файл.

     S    Такие сообщения более серьезны чем сообщения типа W,
но все-таки создадутся выходные файлы.  Однако,  маловероятно,
чтобы программа была выполнена без корректировки ошибок.

     F    Такие сообщения  указывают  на фатальные ошибки,  не
приводящие к появлению выхода.

     U    Такие сообщения указывают на необнаружимые ошибки,
также не приводящие к появлению выхода.

     Далее приведены сообщения об ошибках,  которые могут воз-
никнуть во время прекомпиляции.


1  Невозможно открыть файл %s
2  Ошибочный синтаксис в столбце %u в строке %u файла %s
3  Ошибочное имя курсора в столбце %u в строке %u файла %s
4  Ошибочное имя оператора в столбце %u в строке %u файла %s
5  Ошибочное имя дескриптора в столбце %u в строке %u файла %s
6  Ошибочное включение имени файла в столбце %u в строке %u
   файла %s
7  Ошибочное условие WHENEVERв столбце %u в строке %u файла %s
8  Ошибочное действие WHENEVER в столбце %u в строке %u файла %s
9  Ошибочная host-переменная в столбце %u в строке %u файла %s
10 Ошибочное расположение оператора в строке %u в файле %s
11 Уже в разделе declare в строке %u в файле %s
12 Отсутствует в разделе declare в строке %u в файле %s
13 Невозможно открыть включенный файл \"%s\" в строке %u в файле
   %s
14 Необъявленное имя курсора \"%s\" в строке %u в файле %s
15 Неопределенное имя оператора \"%s\" в строке %u в файле %s
16 Невозможно открыть курсор в строке %u в файле %s
17 Невозможно провести грамматический анализ оператора в строке
   %u в файле %s
18 Ожидалось \"%s\", но обнаружено \"%s\" в строке %u в файле %s
19 Невозможно существование связанных переменных в строке %u в
   файле %s
20 Невозможно существование define-переменных в строке %u в
   файле %s


                            - 157 -

21 Ошибка ORACLE'a: %s
22 Выход за ограничение по памяти - невозможно расположить %u
   байт
23 Невозможно осуществить log off из ORACLE'a
24 Indicator-переменная \"%s\" имеет ошибочный тип или длину в
   строке %u in
25 Необъявленная indicator-переменная \"%s\" в строке %u в файле
   %s
26 Необъявленная host-переменная \"%s\" в строке %u в файле %s
27 Объявленный снова курсор \"%s\" в строке %u в файле %s
28 Объявленное снова имя оператора \"%s\" в строке %u в файле %s
29 Неясная опция \"%s\"
30 Задан ошибочный указатель ранга
31 Ошибочный операнд \"%s\" для опции \"%s\"
32 Ошибочная опция \"%s\"
33 Отсутствующий операнд для опции \"%s\"
34 Невозможно создать модуль доступа (access module)
35 Не задан host-язык
36 Не задано имя входного файла
37 Невозможно осуществить log on в ORACLE с \"%s\"
38 Невозможно открыть курсор
39 Невозможно открыть входной файл \"%s\"
40 Невозможно открыть listing-файл \"%s\"
41 Невозможно открыть output-файл \"%s\"
43 Выход за пределы ограничения по памяти
44 Ограничитель массива не соответствует в INTO/USING.
   Минимумом является: %s(%u:%u)
45 Неподходящая конструкция FOR в строке %u в файле %s.
   Игнорируется.


СООБЩЕНИЯ ОБ ОШИБКАХ PC0.
----------------------

1000  Ошибочный символ \"%c\" в indicator-области в строке %u в
      файле %s
1001  Отличный от пробела символ \"%c\" в области A в строке %u
      в файле %s
1002  Ошибочное продолжение литерала в строке %u в файле %s
1003  Литерал открыт в конце файла
1004  Псевдо-текст открыт в конце файла
1005  В операторе EXEC в конце файла
1006  PROCEDURE DIVISION не обнаружена
1007  Ошибочный ограничитель литерала в строке %u в файле %s

СООБЩЕНИЯ ОБ ОШИБКАХ PC1.
--------------------

1100  Ошибочный указатель в строке %u в файле %s
1101  В одной строке программы %u в файле %s требуется слишком
      много дескрипторов
1102  Невозможно сгенерировать дескриптор в строке, завершающей
      программу, %u в файле %s
1103  Выход за указатель ранга в строке %u в файле %s
.


                            - 158 -

СООБЩЕНИЯ ОБ ОШИБКАХ PC2.
----------------------
1200 Слишком много дескрипторов требуется в строке программы %u
     в файле %s
1201 Невозможно сгенерировать дескриптор в строке программы %u
     в файле %s



ОШИБКИ ВРЕМЕНИ ВЫПОЛНЕНИЯ
--------------------------------------------Д

     2100 PCC: Out of Memory (i.e., couldn't allocate).
     Выход за  ограничение  по  памяти  (например,  невозможно
     расположить)
Встречается, когда  происходит  ошибка в malloc() в библиотеке
времени выполнения прекомпилятора. Это может встретиться, ког-
да  PRO*C  пытается  расположить/увеличить кэш-память курсора.
Программа слишком велика для выполнения;  нет способов исправ-
ления.
     2101 PCC: Inconsistent cursor cache (uce/cuc mismatch).
     Несовместимая кэш-память курсора (несоответствие uce/cuc).
     Это внутренняя ошибка, означающая, что были разрушены ли-
бо  кэш-память курсора либо элемент курсора.  Курсоры PRO*C по
ссылкам являются "устройство зависимыми".  Когда Вы выполняете
PCC  программы,  PRO*C  генерирует  массив  Unit  Cursor Entry
(uce),  называемый sqlcun, который содержит порядковый номер в
кэш-памяти курсора (0 означает, что курсор PCC неоткрыт). Ког-
да курсор PRO*C открыт, он задает cuc.
     2102 PCC:  Inconsistent  cursor  cache  (no cuc entry for
     this uce).Несовместимая кэш-память курсора (нет  элемента
     cuc для этого uce).
     Это внутренняя ошибка,  которая может  встретиться,  если
uce содержит  порядковый  номер  cuc,  но  когда прекомпилятор
смотрит туда,  он не находит элемента  cuc.  Это  "невозможное
условие"  встречается только,  если пользовательская программа
переполняет доступную память.
     2103 PCC:  Inconsistent  cursor  cache  (out-of-range cuc
     ref).  Несовместимая кэш-память курсора  (выход  за  ранг
     ссылки cuc).
     Внутренняя ошибка,  которая может встретиться,  если  uce
содержит порядковый номер в cuc,  который либо слишком большой
либо меньше нуля. Указывает на проблему с памятью.
     2104 PCC: Inconsistent cursor cache (no cuc available).
     Несовместимая кэш-память курсора (cuc недоступен).
     Эта ошибка  указывает на то,  что нет кэш-памяти курсора.
Указывает на проблему с памятью.
     2105 PCC:  Inconsistent  cursor  cache  (no  cuc entry in
     cache).  Несовместимая кэш-память курсора  (в  кэш-памяти
     нет элемента cuc).
     При определенных условиях библиотека  времени  выполнения
(runtime  library)  выполняет  общую  "проверку последователь-
ности" кэш-памяти курсора. Если эта проверка обнаруживает, что
элемент  кэш-памяти курсора таинственно исчез,  то результатом
является сообщение. Указывает на проблему с памятью
     2106 PCC:  Inconsistent  cursor  cache  (OraCursor  nr is
     bad).  Несовместимая кэш-память курсора (номер  OraCursor
     некорректный).
     Это сообщение появляется,  если библиотека времени выпол-
нения обнаруживает ошибочное число курсоров ORACLE'a, во время
попытки операции ORACLE'a.
.


                            - 159 -











ПРИЛОЖЕНИЕ B. ОБЩИЕ ПРОГРАММНЫЕ НАПРАВЛЕНИЯ
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН

     Квалифицируйте все  имена  объектов:  Вы  можете  владеть
большинством объектов (таблицы,  экранны формы, индексы итд.),
к которым Вы имеете доступ в Ваших собственных программах. Од-
нако, для доступа к данным другого пользователя или для разре-
шения другим пользователям запускать программы с Вашими данны-
ми,  Вы  должны полностью квалифицировать имена объектов.  Это
значит,  что Вы должны префиксировать имена объектов именем их
сохдателя  или владельца.  Например,  для выделения из таблицы
ADDRESSES, владельцем которой является FONZIE, Вы могли бы за-
кодировать что вроде:

     EXEC SQL SELECT NAME FROM FONZIE.ADDRESSES;

     Ссылки на таблицы, владелец которых имеет имя пользовате-
ля вроде OP$SCOTT, являются годными, так же как и в SQL*Plus.
     Вы должны присвоить доступ к объекту для выполнения жела-
емой  операции,  и  Вы  должны коррктно сослаться на пользова-
тельскоe имя пользователя в ORACLE'e и имя объекта.
     Следование этой практике  сделает  Ваши  программы  более
компактными и легкими в обслуживании.

.


                            - 160 -











ПРИЛОЖЕНИЕ С. РЕЗЕРВИРОВАННЫЕ СЛОВА
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН


     Резервированные слова являются ключевыми словами, которые
использует ORACLE,  и которые пользователи не могут  использо-
вать для имен объектов,  таких как таблицы, столбцы или экран-
ные формы. Если Вы небрежно используете резервированное слово,
обычное  сообщением об ошибке будет о том,  что это слово "not
valid name".


ADD              ALL            ALTER          AND
ANY              AS             ASC            ASSERT
ASSIGN  AT       BETWEEN        BY             CHAR
CLUSTER          COLUMN         COMPRESS       CONNECT
CONTAIN          CONTAINS       CRASH          CREATE
CURRENT DATABASE DATAPAGES      DATE           DBA
DECIMAL          DEFINITION     DELETE         DESC
DISTINCT         DOES           DROP           EACH
ELSE    ENDIF    EVALUATE       EXCLUSIVE      FILE
FLOAT            FOR            FROM           GRANT
GRAPHIC          GROUP          HAVING         IDENTIFIED
IF      IFDEF    IMAGE          IMMEDIATE      IN
INCREMENT        INDEX          INDEXED        INDEXPAGES
INITIAL          INSERT         INTEGER        INTERSEC
INTO             IS             LEVEL          LIKE
LIST             LOCK           LONG           MAXEXTENTS
MINUS            MODE           MODIFY         MOVE
NEW              NOCOMPRESS     NOSYSSORT      NOT
NOWAINT          NULL           NUMBER         OF
OLD              ON             OPTIMIZE       OPTION
OR       ORACLE  ORDER          PARTITION      PCTFREE
PRIOR            PRIVILEGES     PUBLIC         RESOURCE
REVOKE           ROW            ROWID          ROWNUM
ROWS             RUN            SELECT         SET
SHARE            SIZE           SMALLINT       SPACE
START  STATEMENT SYNONYM        SYSDATE        SYSSORT
TABLE            THEN           TO             TRIGGER
UID              UNION          UNIQUE         UPDATE
USER             USING          VALIDATE       VALUES
VARCHAR          VARGRAPHIC     VIEW           WHERE
WITH             STATEMENT      UID            USER


.


                            - 161 -











ПРИЛОЖЕНИЕ D. ПРИМЕР ПРОГРАММЫ PRO*C
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН


     Приложение D дает пример программы PRO*C.


/* VOID sample

sample  простой пример программы,  которая добавляет записи  о
        служащих  к  базе данных о персонале.  Проверка прово-
        дится для того,  чтобы убедиться  в  целостности  базы
        данных.  Номера служащих выбираются автоматически при-
        бавлением 10 к максимальному номеру  служащего.  Прог-
        рамма  запрашивает пользователя о данных следующим об-
        разом:

        Enter employee name:
        Enter employee job:
        Enter employee salary:
        Enter employee dept:

        Программа завершается,  если вводится символ ^Z (конец
        файла)   или   нажимается   возврат  каретки  (клавиша
        ), когда требуется ввести имя служащего.

        В случае успешного добавления записи будет  напечатано
        следующее:

        ename добавляется к названию отдела dname как employee
        # nnnnnn

        Чтобы создать и запустить SAMPLE:

            C> pcc iname=sample.pc include=\oracle\dbs
               prog=sample host=c userid=scott/tiger
            C> lcc sample
            C> link \lc\s\c.obj + sample.obj, sample,
               sample.map,\oracle\dbs\pcclcs.lib +
               \lc\s\lc.lib
            C> sample

        "lcc" является шагом компиляции,  который берет файл с
        расширением  .C  из  PCC  и создает файл с расширением
        OBJ, необходимый редактору связей.
*/

#include 
#include 

EXEC SQL BEGIN DECLARE SECTION;


                            - 162 -

VARCHAR uid[20];              /* имя пользователя */
VARCHAR pwd[20];              /* пароль */
int  empno;                   /* номер сотрудника */
VARCHAR ename;[15];

int  deptno;                  /* имя сотрудника */
VARCHAR dname[15];            /* номер отдела */

VARCHAR job[15];              /* название отдела  */

int  sal;                     /* работа сотрудника */
EXEC SQL END DECLARE SECTION  /* заработок сотрудника */
EXEC SQL INCLUDE SQLCA;

main()
{

/* ---------------------------------------------------------
Осуществляет logon к ORACLE'у, и открывает курсоры. Выход
из программы осуществляется при обнаружении любой ошибки.
------------------------------------------------------------*/

   strcpy(uid.arr,"SCOTT");
   uid.len = strlen(uid.arr);
   strcpy(pwd.arr,"TIGER");
   pwd.len = strlen(pwd.arr);

   EXEC SQL WHENEVER SQLERROR GOTO errexit;
   EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;

/* -------------------------------------------------------------
Восстанавливает текущий максимум номера сотрудника
------------------------------------------------------------- */

   EXEC SQL SELECT NVL(MAX(EMPNO),0) + 10
              INTO :empno
              FROM EMP;

/*--------------------------------------------------------------
читает ввод пользователя из STDIN.  Если имя сотрудника не было
введено, то выход из программы.
Проверяет, что введенный номер отдела является годным и
повторяет название отдела
-------------------------------------------------------------- */

     for( ; ; empno+=10 )
               {
               int l;
               /* Дает ввести имя сотрудника.

        ВАЖНОЕ ЗАМЕЧАНИЕ: остерегайтесь от следующего кодирования

     ename.len = asks("Enter employee name  : " , ename.arr);
                                   if ( ename.len <= 0 )
                                        ..итд..

     Выше, asks() возвращает int,  но ename.len знаконеопреде-
ленное, короткое (смотри SQLCA).
     Therefore, the  "if"  fails  for  (which returns -1)
because,  by definition, the unsigned short can't be negative.
*/


                            - 163 -

          l = asks("Enter employee name  : ",ename.arr);

     if ( l <= 0 )
               break;

     ename.len = l;
        job.len = asks("Enter employee job   : ",job.arr);
     askn("Enter employee salary: ",&sal);
     for ( ; ; )
               {
   if ( askn("Enter employee dept  :    ",&deptno) < 0 )
   break

      EXEC SQL WHENEVER NOT FOUND GOTO nodept;
      EXEC SQL SELECT DNAME
                 INTO :dname
                 FROM DEPT
                 WHERE DEPTNO = :deptno;
      dname.arr[dname.len] = '\0';

      EXEC SQL WHENEVER NOT FOUND STOP;

      /* Here if deptno was found in dbs.
         Insert new employee into dbs. */

      EXEC SQL INSERT INTO EMP(EMPNO,ENAME,JOB,SAL,DEPTNO)
                 VALUES (:empno,:ename,:job,:sal,:deptno);


printf("\e%s added to the %s department as employee number %d\n",
       ename.arr,dname.arr,empno);
     break;
     /* Здесь, если deptno не (NOT) найдено в dbs */
      nodept,
        printf("\nNo such department\n");
        continue;
      }
   }
/* -------------------------------------------------------------
закрывает курсоры и осуществляет log off из ORACLE'a
------------------------------------------------------------- */

   EXEC SQL COMMIT WORK RELEASE;
   printf ("\nEnd of the C/ORACLE example program.\n");
   return(1);

errexit,
   errrpt();
   EXEC SQL ROLLBACK WORK RELEASE;
   return(0);
}
.


                            - 164 -

/*------------------------------------------------------
COUNT askn(text,variable)

   печатает 'text' в STDOUT и читает целочисленную переменную из

SDTIN.

text points to the null terminated string to be printed
variable points to an integer variable
askn returns a 1 if the variable was read successfully or a
    -1 if -eof- was encountered
-------------------------------------------------------------- */

int askn(text,variable)
   char text[];
   int  *variable;
   {
   char s[20];
   printf(text);
   if ( gets(s) == (char *)0 )
   return(EOF);

   *variable = atoi(s);
   return(1);
   }
/* --------------------------------------------------------------
COUNT asks(text,variable)

печатает 'text' в STDOUT и читает символы до 'len' в буффере,
указанном при помощи переменной из STDIN.

text указывает на стринг, оканчивающийся нулевым символом, и
который необходимо распечатать;
variable указывает на буффер с, по меньшей мере,   ('len'+1)-
символами

asks возвращает число символов, прочитанных в стринг, или
было обнаружена  -1, если -eof- (конец файла)
-------------------------------------------------------------- */

int asks(text,variable)
   char text[],variable[];
   {
   printf(text);
   return( gets(variable) == (char *)0 ? EOF : strlen(variable));
   }


/* -------------------------------------------------------------
VOID errrpt()

   errrpt печатает сообщения об ошибках ORACLE и их число.
-------------------------------------------------------------- */
errrpt()
  {
  printf("\n%.70s (%d)", sqlca.sqlerrm.sqlerrmc, -sqlca.sqlcode);
  return(0);
  }


                            - 165 -








ПРИЛОЖЕНИЕ E. ПРИМЕР ПРОГРАММЫ PRO*C С ДИНАМИЧЕСКИМ SQL
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН



     Приложение E  представляет   программу   PRO*C,   которая
использует динамический SQL.

  /* Copyright (c) 1984 by Oracle Corporation. */

  #include 
  #include 
  #include "orastd.h"

  /*
  ИМЯ
    MU : Mini-UFI.
  ФУНКЦИЯ
    Пример аналогичной UFI программы,  предназначенной для де-
монстрации динамических операторов SQL с прекомпилятором C.


    Для создания MU (на VMS):

      $ PCC INAME=MU.PC PROG=MU USERID=/ INCLUDE=SYS$ORACLE:
      $ CC MU
      $ @SYS$ORACLE,LOUTL MU MU,SYS$ORACLE,SQLLIB/LIB MU S
      $ RUN MU

    Для создания MU (на VM/CMS),

      PCC INA=MU.CSQL
      CC MU
      LINKSQL MU
      MU


  #uedef T
  #undaf F

  #define         CR    13

     EXEC SQL BEGIN DECLARE SECTION;
          VARCHAR  uid[30];   /* userid       */
          VARCHAR  psswd[30]                         /* пароль */
          char       *stmt;
/*Вводимый пользователем оператор SQL*/

     EXEC SQL END DECLARE SECTION;

     EXEC SQL INCLUDE SQLCA;
     EXEC SQL INCLUDE SQLDA;


                            - 166 -

SQLDA  *bdp;
/* ->Дескриптор используется для переменных BIND*/
SQLDA  *sdp;
/* ->Дескриптор используется для переменных SELECT*/
short  *sdt = 0;
/* ->массив исходно описаннных (DESCRIBE'd) типов */
int       sdtl;
/* число элементов в sdt[]      */
char  *vars = 0;
/* -> область, используемая для хранения переменных Bind */
int       bdSize = S;
/* Размер дескриптора переменной BIND */
int       bvSize = 10;
/* Максимальное число символов в имени переменной типа Bind */
int       sdSize = S;
/* Размер дескриптора  Select List */
int       svSize = 80;
/* Максимальное число символов в именах столбцов Select List */
int       autoCom = FALSE;
/* Выполнить автоматические сблокировки? */
int       done = FALSE;
/* Выполнены выполнимые операторы?      */
int       reExec;
/* Выполнить снова тот же оператор sql?  */
extern  char  *malloc();
/* Расположить память       */
extern  char  *sglald();
/* Расположить дескриптор       */
extern  VOID   mufwrn();
/* Напечатать сообщение об ошибке SQLWARNING */

main(argc, argv)
     int  argc;
     char  *argv[];
{
   int    i;
   int    firstTime;      /* Оператор выполняется впервые ? */
   char   answer[4];/*Стринг для хранения ответов на вопросы*/

 /* начало mu */

 printf("MU V1.1  Interactive SQL Statement Executor\n\n");
 printf("For help, type '/help;' at the prompt.\n");

login(argc, argv);

/* Располагает память для различных дескрипторов и стрингов  */
/*которые будут использоваться, и задает первый командный стринг
*/
stmt = malloc(256);

if ( stmt == NULL )
  {/* Problem alloc'ing memory?!? */
  puts("MU FAIL stmt = malloc(256)");
  exit(EX_FTL);
  }

bdp = sqlald(bdSize, bvSize, 10);

if ( bdp == NULL )
  {/* Problem allocating memory?!? */


                            - 167 -

  puts("MU FAIL: bdp = sqlald(bdSize, bvSize, 10)");
  exit(EX_ETL);
  }

sdp = sqlald(sdSize, svSize, 0);
/*Располагает новый дескриптор*/

if ( sdp == NULL )
  {/* Problem allocating memory?!? */
  puts("MU FAIL: sdp = sqlald(sdSize, svSize, 0)");
  exit(EX_FTL);
  }

sdp->N = 0;
/* инициализирует в случае выхода перед DESCRIBE */

while (!getCom(stmt));

/* Начало главного цикла */
while (!done)
  {
  EXEC SQL WHENEVER SQLERROR  GOTO CHECKERR,            */
/*Обрабатывает любую псевдо-команду,
которую вводит пользователь*/
  while (stmt[0] =='/')

   {
   procCmd(&stmt[1]);     /* Обрабатывает псевдо-команду */
   if (done) break;       /* Не берет другой оператор */
   while (!getCom(stmt)); /* Берет другую команду */
   }
if (done) break;     /* Выход из цикла и обнуление */
/* Проводит грамматический анализ введенного оператора */
EXEC SQL PREPARE S FROM :stmt;

if ( sqlca.sqlwarn[0] == 'W' )
mufwrn();  /* Выдает сообщение об ошибке SQLWARNING */

EXEC SQL DECLARE C CURSOR FOR S;

/* Описывает переменные типа bind в bdp дескриптора   */
bdp->N = bdSize;
descBind();

firstTime = TRUE;
  /* Обратите внимание на тот факт, что это впервые,  */
  /* когда был выполнен этот оператор */

/* Следующий цикл выполняет оператор, проанализированный выше */
/* и выше с различными значениями для переменных типа bind. */
do
  {
  if (bdp->E != 0) getBVVals(&vars);
  EXEC SQL OPEN C USING DESCRIPTOR bdp;
  if (firstTime)
    {
    firstTime = FALSE;
    sdp->N = sdSize;
    descSel();       /* Описывает переменные select list  */
    if (sdp->F != 0) fillSelDesc();
    }


                            - 168 -

if (sdp->N != 0) doFetches();
else
    {
    printf("%u rows processed.\n", sqlca.sqlerrd[2]);
    if (autoCom) commitWork();
    }

  reExec = FALSE;
  for (; ;)
    /* UNTIL cmd == SQL statement !! /exit !!/run      */
    {
    while (!getCom(stmt));
    if (stmt[0] != '/') break;    /* Got SQL statement  */
    procCmd(&stmt[1]);
    if (done !! reExec) break;    /* Got /exit !! / run */
    }

  } while(reExec);

EXEC SQL CLOSE C;
if (sdp->N ]= 0) freeSelVars();
if (vars ]= 0) {free(vars); vars = 0;}
continue;


CHECKERR:
  reptError();
  sqlca.sglcode = 0;
  printf("\nCare to continue? ");
  fflush(stdout);
  gets(answer);
  if (toupper(answer[0]) !='Y')
    {/* Пользователь не хочет продолжать. Rollback и выход. */
    rollBkPr();
    break;
    }

   /* Здесь, если пользователь хочет продолжать после ошибки. */

     while (!getCom(stmt));
  }

cleanUp();
EXEC SQL COMMIT WORK RELEASE;
return;

ERR_EXIT:
  reptError();
  cleanUp();
  EXEC SQL WHENEVER SQLERROR CONTINUE;
  EXEC SQL ROLLBACK WORK RELEASE;
  return;

/* конец mu */
}

EXEC SQL WHENEVER SQLERROR STOP;
EXEC SQL WHENEVER SQLWARNING CONTINUE;
EXEC SQL WHENEVER NOT FOUND CONTINUE;


                            - 169 -

/** mufwrn : Выдает сообщение SQLWARNING. */

VOID        mufwrn()
{
/* начало mufwrn */

if( sqlca.sqlwarn[1] == 'W' )
  puts("SQLWARNING: Column was truncated.");
else if ( sqlca.sqlwarn[2] == 'W' )
puts("SQLWARNING: Null values in aggregate (MAX, SUM)function.");
else if (  sqlca.sqlwarn[3] =='W' )
  puts("SQLWARNING: INTO var count not equal column count.");
else if ( sqlca.sqlwarn[4] == 'W' )
  puts("SQLWARNING: Update or Delete without Where clause.");
else if ( sqlca.sqlwarn[5] == 'W' )
  puts("SQLWARNING: ???.");
else if ( sqlca.sqlwarn[6] == 'W' )
  puts("SQLWARNING: Rollback reguired.");
else if ( sqlca.sqlwarn[7] == 'W' )
  puts("SQLWARNING:Change after query start on Select For
Update.");

/* конец mufwrn */
}

cleanUp()
{
  if (sdp->N ]= 0) freeSelVars();
  if (vars ]= 0) {free(vars); vars = 0;}...
  sqlclu(bdp);/* Освобождает дескриптор переменных типа bind */
  sqlclu(sdp);         /* Освобождает дескриптор select list */
}
getCom(s)
char *s;
{
  int i, l;
  char temp[256];

  printf("MU: ");
  fflush(stdout);
  gets(s);
  if ((l=strlen(s)) < 2) return(FALSE);
  if (s[l-1] == ';') {s[l-1] = '\0'; return(TRUE);}
  for (i = 2; ; i++)
    {
    printf("%*u: ", 2, i);
    fflush(stdout);
    gets(temp);
     strcat(s, " ");
     strcat(s, temp);
     if (s[(l=strlen(s)-1)] == ';')
          {s[l] = '\0'; return(TRUE);}
     }
}

print(dp)
SQLDA *dp;
{
  int   i;
  int  *vp;
  short  *ip;


                            - 170 -

/* начало печати */

for (i = 0; i < dp->N; i++)
  {
  ip = dp->I[i];
  if (*ip < 0)        /* возвращает значение при нуле */
    printf("%-*s ", dp->L[i], " ");
  else
    printf("%-.*s ",dp->L[i], dp->V[i]);
  }

putchar('\n');

/* конец печати */
}

descBind()
{
   EXEC SQL DESCRIBE BIND VARIABLES FOR S INTO bdp;
   if (bdp->F < 0)   /* Дескриптор не достаточно большой */
     {
     bdSize = -(bdp->F);
     sqlclu(bdp);    /* Избавляется от текущего дескриптора */
     bdp = sqlald(bdpSize, 10, 0);
/*Располагает правильный размер*/
     EXEC SQL DESCRIBE BIND VARIABLES FOR S INTO bdp;
     }
  bdp->N = bdp->F;
}

login(argc, argv)
  int   argc;
  char  *argv[];
{
/* начало login */

if ( argc == 2 )
  {/*Вызывающий предусматривает usr/pwd (пользователь/пароль). */
  strcpy(uid.arr,argv[1]);
  uid.len  = strlen(argv[1]);
  psswd.len = 0;
  EXEC SQL CONNECT :uid;
  if ( sqlca.sqlcode == 0 )
    return;

  puts("Problem logging in, please try again...\n");
  }

for ( ; ; )
  {
  printf("Username: ");
  fflush(stdout);
  gets(uid.arr);
  if (uid.arr[0] == '0') return;
     uid.len = strlen(uid.arr);
     printf("Password: ");
     fflush(stdout);
     gets(psswd.arr);
     psswd.len = strlen(psswd.arr);

     EXEC SQL CONNECT muid IDENTIEIED BY :psswd;


                            - 171 -

     if ( sqlca.sqlcode == 0 )
       {
       puts("Successfully connected.\n");
       break;
       }
     puts("Problem logging in, please try again...\n");
     }

   EXEC SQL WHENEVER SQLERROR STOP;
   /* конец login */
  }

  getBVVals(vars)
/* Дает пользователю задать значения для каждой из переменных
типа bind. */
/* Располагает 10-байтный стринг
для каждой переменной типа bind. */
  char **vars;
/*пойнтер за пойнтером для хранения переменных типа bind*/
  {
    int i;
    if (*vars == 0)
      {
      *vars = malloc((bdp->F) * 10);
      if ( *vars == NULL )
        {/* Problem allocating memory?]? */
        puts("MU FAIL: *vars = malloc((bdp->F) * 10)");
        exit(EX_FTL);
     }
   }

/* Располагает 10-байтный стрингдля хранения значения, которое
   пользователь задает для каждой переменной типа bind. */
printf("Please enter values for the bind variables: n");
for (i = 0; i < bdp->E; i++)
  {
  printf(''%.*s. ", bdp->C[i], bdp->S[i]);
  bdp->V[i] = &((*vars)[i*10]);
  fflush(stdout);
  gets(bdp->V[i]);
  bdp->T[i] = 1;
  bdp->L[i] = strlen(bdp->V[i]);
  bdp->I[i] = 0;
  }
}

descSel()
/* Описывает переменные select list в sdp, увеличивая если
     необходимо. Устанавливает предписываемый размер числу
     найденных столбцов. */
{
  EXEC SQL DESCRIBE SELECT LIST FOR S INTO sdp;
  if (sdp->F < 0)       /* дескриптор не был достаточно велик */
    {
    sdSize = -(sdp->F);        /* сохранит правильный размер */
    sqlclu(sdp);           /* Освободит маленький дескриптор */
    sdp = sqlald(sdSize, 10, 0);/* Расположит корректный размер*/
    EXEC SQL DESCRIBE SELECT LIST FOR S INTO sdp;
    }
  sdp->N = sdp->F;
}


                            - 172 -

/**  doFetches()

  Печатает заглавия столбцов, выполняет захваты и вызывает пе-
  чать для каждой найденной строки. Печатает число найденных.
*/
doFetches()
{
  int   cnt;
  char   colname[100];
  int   colnamel;

/* начало doFetches */

EXEC SQL WHENEVER NOT FOUND GOTO NOT_FND;

/* печатает имена столбцов */

putchar('\n');

for (cnt = 0; cnt < sdp->N; cnt++)
{/*Печатает имя столбца: выравнивание по правому краю для
     символов; по правому краю для чисел.*/
  colnamel = min(sdp->L[cnt],sdp->C[cnt]);
  colnamel = min(colnamel,sizeof(colname)-1);
  memcpy(colname,sdp->S[cnt],colnamel colname[colnamel] = '\0';

if ( sdt[cnt] == 2 )
  {/* ЧИСЛО: выравнено по правому краю. */
  printf("%*s ", sdp->L[cnt],colname);
  }
else
  {/* НЕЧИСЛО: выравнено по левому краю. */
  printf("%-*s ", sdp->L[cnt],colname);
  }
}


/* Подчеркивание имен столбцов     */

putchar('\n');

for (cnt = 0; cnt < sdp->N; cnt++)
  {
  int i;

  for (i = 0; i < sdp->L[cnt]; i++)
    putchar('-');

  putchar(' ');
  }

putchar('\n');

/* На самом деле выполняет захваты и печатает результаты */

for (cnt = 0; ; cnt++)
  {
  EXEC SQL FETCH C USING DESCRIPTOR sdp;
  print(sdp);   /* Печать результатов захвата */
  }


                            - 173 -

NOT_FND, printf("\n%u row(s) selected\n", cnt);

EXEC SQL WHENEVER NOT FOUND CONTINUE;

/* конец doFetches */
}

/**    fillSelDesc : Fill SELECT Descriptor.
  Allocate storage for each of the select list vars, and
  allocate storage for an indicator variable for each column
*/
fillSelDesc()
{
  int    i;
  unsigned char spec;
  char    scale;

/* начало fillSellDesc */

if ( !sdt)
  {/* Сейчас sdt[] не был размещен. */
  sdt = (short *)malloc(sizeof(short) *  sdp->N); }
else if ( sdtl < sdp->N )
  {/* Для нового размещения необходимо сохранить тип массива. */
  sdt = (short *)realloc(sdt,sizeof(short) * sdp->N); }

sdtl = sdp->N;

for (i = 0; i < sdp->N; i++)
  {
  /* Сохранение исходного типа; и очистка возможного NULL
     бита стршего порядка.
  */
  sdp->T[i] = (sdp->T[i] &  0x8000);
  sdt[i]   = sdp->T[i];

  if ( sdp->T[i] == 2 )
    {/* Имеет NUMBER. Необходим для точности и шкалы. */
    prec  = (unsigned char)(sdp->L[i] >> 8);
    scale = (char)sdp->L[i];

    if ( prec == 0 )
      {/*Без точности. Пользовательское значение по умолчанию. */
      prec = 26;
      }
    sdp->L[i] = prec;

    if ( scale < 0 )
      {/* Have -scale. Need to add trailing zeros. */
      sdp->L[i] += -scale;
      }
    sdp->L[i] += 2;/*+2 для возможного знака и десятичной точки*/
    }

  else if ( sdp->T[i] == 12 )
    {/* Имеет DATE. Необходима для установки значения по
умолчанию len для DD-MON-YY. */
    sdp->L[i] = g;
    }



                            - 174 -

  /* Обращает в CHAR, с максимальной длиной = 240. */

  sdp->T[i] = 1;
  sdp->L[i] = min(sdp->L[i],240);
  sdp->V[i] = malloc(sdp->L[i]);
  sdp->I[i] = malloc(sizeof(short));
  }

/* конец fillSelDesc */
}

freeSelVars()
/* Освобождает память, предназначенную для хранения захваченных
значений */
{
  int i;
  for (i = 0; i < sdp->N; i++)
    {
    free(sdp->V[i]);
    free(sdp->I[i]);
    }
  sdp->N = 0;  /* устанавливает необходимым "have free()'d
fetched-val storage" */
}

/* Псевдо-командные процедуры, псевдо-командный процессор, и
   поддержка программ для этого.         */

/* Псевдо-командные процедуры         */

setReExecPr() {reExec = TRUE;}
resetAutoPr() {autoCom = FALSE;
               printf("No longer in AutoCommit mode\n");}
setAutoPr() {autoCom = TRUE;
            printf("Now in AutoCommit mode\n");}
setDonePr() {done = TRUE;}
rollBkPr() {rollBackWork(); printf("Work Rolled Back\n");}
commitPr()  {commitWork();
             printf("Work Committed\n");} helpPr()
{
  printf("\nMU V1.1 Help\n");
  printf("To execute a SQL statement, simply type the
statement\n");
  printf("when given the prompt.  The statement may  be
entered\n");
  printf("on several lines and must be terminated by a ';'.
In\n");
  printf("fact, all commands must be terminated by a '; '.
There\n");
  printf("are several pseudo commands which begin with a
'/'.\n");
  printf("\nThe pseudo commands are:\n");
  printf("  /c[ommit]    Commit Work\n");
  printf("  /ro[llback]  RollBack Work\n");
  printf("  /ru[n]       Reexecute the last SQL statement\n");
  printf("  /e[xit]      Exit this program\n");
  printf("  /a[uto]      Enter AutoCommit Mode\n");
  printf("  /m[anual]    Exit AutoCommit Mode\n");
  printf("  /h[elp]      Get this information\n");
  printf("For more detailed information, read the code.\n");
}}


                            - 175 -

/* Таблица псевдо-команд и командный процессор       */

struct comTabEntry {
  char *cmd;    /* Единственный префикс псевдо-команды */
  int  (*proc)();    /* процедура вызова        */
  } comTab[] =
  {"c"    commitPr,
   "ro",  rollBkPr,
   "ru",  setReExecPr,
   "e",   setDonePr,
   "a",   setAutoPr,
     "m",   resetAutoPr,
     "h",   helpPr,
      "",   0};

procCmd(s)
char *s;
{
  int i;
  int (*proc)();

  if (strlen(s) == 0) return;
  for (i = 0; comTab[i].proc; i++)
    if (isPrfx(comTab[i].cmd,s))
      {proc = comTab[i].proc; (*proc)(); return;}
  printf(''\nUnrecognized Commandm %s\n'', s);
}
/*Поддержка процедур для псевдо-команд и процессор псевдо-
команд*/
isPrfx(prfx, s)
char *prfx, *s;
{
  int i, l;.
  if ((l=strlen(prfx)) == 0) return(FALSE);
  for (i = 0; i < l; i++)
    {
    if ( toupper(*prfx) ]= toupper(*s) )
      return(FALSE);
    prfx++;
    s++;
    }
  return(TRUE);
}
rollBackWork()
{
  EXEC SQL ROLLBACK WORK;
}
commitWork()
{
   EXEC SQL COMMIT WORK;
}
/* Разнообразная поддержка программ           */
reptError()
{
  printf("%.70s\n", sqlca.sqlerrm.sqlerrmc);
}


                            - 176 -





ПРИЛОЖЕНИЕ F. ПРИМЕР ПРОГРАММЫ НА С
НННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН

     Это приложение содержит завершенную программу на С, кото-
рая  запрашивает  пользователя о вводе (информация о сотрудни-
ках) и,  после выполнения некоторой проверки,  добавляет новые
записи о сотрудниках в базу данных.
     Этот пример  был  написан  с  использованием  компилятора
VAX/VMS C.  Программа доступна в следующих файлах на дистрибу-
тивном носителе:

     VAX/VMS   DEMO$
     :SAMPLE.


#include 
#include 
/*
       **ОПРЕДЕЛЯЕТ ВЕРСИЮ С КУРСОРА (ДЛЯ 32-БИТНЫХ МАШИН)
*/
struct csrdef
{
   short  csrrc;              /* возвращает код */
   short       csrft;         /* тип функции */
   unsigned long  csrrpc;     /* счетчик обработанных строк */
   short       csrpeo;        /* parse error offset */
   unsigned char  csrfc;      /* код функции */
   unsigned char  csrfil;     /*  filler  */
   unsigned short csrarc;     /* reserved private */
   unsigned char  csrwrn;     /* предостерегающие флаги */
   unsigned char  csrflg;     /* флаги ошибок */
   /*    *** Зависит от операционной системы ***   */
   unsigned int  csrcn;       /* номер курсора */
   struct {                   /* структура rowid */
   struct {
     unsigned long  tidtrba; /* rba первого блока таблицы */
     unsigned short  tidpid; /* partition id таблицы */
     unsigned char  tidtbl;  /* table id of table */
       }         ridtid;
     unsigned long   ridbrba;/* rba блока данных */
     unsigned short  ridsgn; /*номер последовательности строки
                               в блоке*/
     } csrrid;
   unsigned int  csrose;   /* зависящий от операционной системы
                              код ошибки */
   unsigned char  csrchk;         /* бит проверки */
   unsigned char  crsfill[26];    /* private, reserved fill */
};

char *uid = "scott/tiger";    /* имя пользователя/пароль */
char *insert = "INSERT INTO EMP(EMPNO,ENAME,JOB,SAL,DEPTNO)
                 VALUES
                 (:EMPNO, :ENAME, :JOB, :SAL, :DEPTNO)";
char *select = "SELECT DNAME FROM DEPT WHERE DEPTNO=:1";
char *maxemp = "SELECT NVL*(MAX(EMPNO), 0) + 10 FROM EMP";
char *selemp = "SELECT ENAME, JOB FROM EMP"; /* find name,
job size */


                            - 177 -

main()
{
   int   empno, sal, deptno; /*employee number, salary, dept
                              number*/
   struct lda;                             /*область lda */
   struct csrdef curs[2];               /* и два курсора */
   char  hst[256];                  /* Определение Host  */
   char *ename,*job,*dept; /*имя сотрудника,работа и отдел*/
   short  enamel, jobl, deptl;
   char  *malloc();

#define LDA &lda
#define C0  (&curs[0])
#define CI  (&curs[1])
#define HST &hst
#define DUPLICATE_VALUE -9  /* HLI interface return code */
#define INT 3                   /* HLI integer type code */
#define CHRSTR 5      /* HLI null terminated string type */
/*
** LOGON К ORACLE'у, ОТКРЫТИЕ ДВУХ КУРСОРОВ.
   ЗАМЕЧАНИЕ: В БОЛЬШИНСТВЕ СИТУАЦИЙ ЭТА ПРОСТАЯ ПРОГРАММА
   ОСУЩЕСТВЛЯЕТ ВЫХОД, ЕСЛИ ВСТРЕЧАЕТ ЛЮБУЮ ОШИБКУ.
*/
   if (orlon(LDA, HST, uid, -1, (char *)0, -1, -1))
   {
      errlda(LDA, "orlon");
      goto errexit;
   }

   if (oopen(C0, LDA, (char *)0, -1, -1, (char *)0, -1))
   {
      errrpt(C0);
      goto errexit;
   }

      if (oopen(C1, LDA, (char *)0, -1, -1, (char *)0, -1))
   {
         errrpt(C1);
         goto errexit;
   }

/*
** ВЫКЛЮЧЕНИЕ AUTO-COMMIT.  ЗАМЕЧАНИЕ: ПО УМОЛЧАНИЮ OFF,
   ТАК ЭТО МОЖЕТ БЫТЬ СБЛОКИРОВАНО.
*/
   if (ocof(LDA))
   {
      errlda(LDA, "ocof");
      goto errexit;
   }
/*
** ВОССТАНОВЛЕНИЕ ТЕКУЩЕГО МАКСИМУМА ЧИСЛА СОТРУДНИКОВ
*/
   if (osgl3(C0, maxemp, -1)
       іі odfinn(C0, 1, (unsigned char *)&empno, sizeof(empno),
          INT,   -1, (short *)0, (char *)0, -1, -1, (short *)0,
          (short *)0)
       іі oexec(C0)
       іі ofetch(C0))
   {  errrpt(C0);
      goto errexit;  }


                            - 178 -

/*
** ОПИСАНИЕ СТОБЦОВ ДЛЯ ЗАДАНИЯ МАКСИМАЛЬНОЙ ДЛИНЫ
** ИМЕНИ СОТРУДНИКА, НАЗВАНИЯ РАБОТЫ.
*/
   if (osgl3(C0, selemp, -1)
      іі odsc(C0, 1, &enamel, (short *)0, (short *)0. (short *)0,
              (char *)0, (short *)0, (short *)0)
      іі odsc(C0, 2, &jobl,   (short *)0, (short *)0, (short *)0,
              (char *)0, (short *)0, (short *)0) )
   {  errrpt(C0);
      goto errexit;  }

   job  = malloc(jobl+1);   /*не забудбте пространство под ноль*/
   ename = malloc(enamal+1);

/* ГРАММАТИЧЕСКИЙ АНАЛИЗ ОПЕРАТОРОВ INSERT И SELECT
** ОПИСАНИЕ dname ТАК ЧТО МЫ МОЖЕМ РАЗМЕСТИТЬ ПРОСРАНСТВО
** ЗАТЕМ ЗАДАТЬ dept */

if (osql3(C0, insert, -1))
{  errrpt(C0),
   goto errexit; }
if (osql3(C1, select, -1)
    іі odsc(C1, 1, &deptl, (short *)0, (short *)0, (short *)0,
         (char *)0, (short *)0, (short *)0)
    іі odfinn(C1, 1, dept = malloc(deptl+1) , deptl+1, CHRST ,
        (short *)0, (char *)0, -1, -1, (short *)0, (short *  0) )
{  errrpt(C1),
   goto errexit; }

/*
** BIND SQL SUBSTITUTION VARIABLE VALUES USING BIND BY REFREN
** STATEMENTS.
*/
   if (   obndrv(C0, ":ENAME", -1, ename, (int)enamel+1, CHRSTR
             -1, (short *)0, (char *)0, -1, -1)
       іі obndrv(C0, ":JOB", -1, job, (int)jobl+1, CHRSTR,
             -1, (short *)0, (char *)0, -1, -1)
       іі obndrv(C0, ":SAL", -1, (unsigned char *)&sal,
sizeof(sal),
             INT, -1, (short *)0, (char *)0, -1, -1)
       іі obndrv(C0, ":DEPTNO",-1, (unsigned char *)&deptno,
sizeof(d eptno),
             INT, -1. (short *)0, (char *)0, -1, -1)
       іі obndrv(C0, ";EMPNO", -1, (unsigned char *)&empno,
sizeof(e mpno),
             INT, -1, (short *)0, (char *)0, -1, -1) )
{     errrpt(C0);
      goto errexit; }



                            - 179 -

/*
** ЧТЕНИЕ ВВОДА ПОЛЬЗОВАТЕЛЯ ИЗ stdin.  ЕСЛИ ИМЯ СОТРУДНИКА
** НЕ ВВЕДЕНО, ТО ВЫХОД. ПРОВЕРКА, ТОГО, ЧТО ВВЕДЕННЫЙ НОМЕР
** ОТДЕЛА ПРАВИЛЕН И  ECHO НАЗВАНИЯ ОТДЕЛА, КОГДА ВЫВОДИТСЯ
** НОВАЯ СТРОКА.
*/


for(  ;
      asks("Enter employee name  : ", ename, enamel, 0) > 0;
      empno += 10)
{
   asks("Enter employee job   : ", job, jobl, 0);
   aski("Enter employee salary ", &sal, 0);
   while (aski(''Enter employee dept  :   '', &deptoo, 0) <= 0
          іі obindn(C1, 1, (unsigned char *)&deptno,
sizeof(deptno ),
              INT,  -1, (char *)0, -1, -1)

          іі oexec(C1)
          іі ofetch(C1))
   {
       printf("\nNo such department %d\n", deptno);
   }

/*
** ВЫПОЛНЕНИЕ ОПЕРАТОРОВ. ЕСЛИ ВСРЕЧАЕТСЯ ПОВТОРЕНИЕ empno,
** ВЫЧИСЛЕНИЕ СЛЕДУЮЩЕГО И ВЫПОЛНЕНИЕ СНОВА.
*/
     while (oexec(C0) == DUPLICATE_VALUE)
     {
        empno += 10;
     }

/*
** ВЫХОД ПРИ ОБНАРУЖЕНИЕ В ЭТОЙ ТОЧКЕ ЛЮБОЙ ОШИБКИ ИЗ OEXEC.
*/
      if (C0->csrrc)
      {
         errrpt(C0);
         goto errexit;
      }

/*
** СБЛОКИРОВАННЫЙ ВВОД ИЗМЕНЕНИЙ В БАЗЕ ДАННЫХ.
*/
      if (ocom(LDA))
      {
         errlda(LDA, "ocom");
         goto errexit;
      }


/*  ** GIVE THE USER SOME FEEDBACK.    */

printf("\n%s added to the %s department as employee number %d\n",
             ename, dept, empno);
}



                            - 180 -

/*  ** ЛИБО ОШИБКА ЛИБО ВВЕДЕННЫЙ ПОЛЬЗОВАТЕЛЕМ END-OF-FILE
            (КОНЕЦ ФАЙЛА) ДЛЯ ИМЕНИ СОТРУДНИКА.
** ЗАКРЫТИЕ КУРСОРОВ И LOG OFF ИЗ ORACLE'a.  */

errexit:
   oclose(C0);
   oclose(C1);
   ologof(LDA);
   printf ("\nEnd of the C/ORACLE example program.\n"),
   return(1);
}

/*
** errlda И errrpt ПЕЧАТЬ КОДА ОШИБКИ, ДРУГАЯ ИНФОРМАЦИЯ.
*/

/*void*/ errrpt(cur)
struct csrdef *cur;         /* пойнтер для курсора */
{
   char  msg[80];
   printf("ORACLE error: code is %d, op is %d\n",
          (int)cur->csrrc, (int)cur->csrfc);
   oermsg(cur->csrrc, msg);
   printf("%s\n",msg);
}

/* void */ errlda(lda,msg)
struct  csrdef *lda;                  /* пойнтер для LDA */
char   msg[];              /* заданное пользователем сообщение */
{
   char   oertxt[80];
   printf ("LDA error (%s): code is %d\n", (int)lda->csrrc);
   oermsg(lda->csrrc, oertxt);

                         printf("%s\n",oertxt);
                      }



                            - 181 -

ПРИЛОЖЕНИЕ G. ИНФОРМАЦИЯ О ВЫЗОВЕ ПРОГРАММ

     Это приложение содержит алфавитный  список  вызовов  всех
OCI,  включающий предыдущие вызовы, используемые для совмести-
мости с ранними версиями СУРБД ORACLE.
     Для каждого вызова,  общий синтаксис показан на примерах,
написанных на C, КОБОЛе и Фортране. Для получения пояснения по
отдельным аргументам, пожалйста обращайтесь к разделу по инте-
ресующему Вас вызову.

Ъ--------------------------------------------------------------Дї
і                         OBIND и OBINDN                        і
і    (Новые программы должны использовать OBNDRN и OBNDRV)      і
Г--------------------------------------------------------------Дґ
і                                                               і
і    CALL OBIND (cursor,sqlvar,[sqlvl],progvar,[progvl],ftype)  і
і                                                               і
і    CALL OBINDN (cursor,sqlvarnum,progvar,[progvl],ftype)      і
і                                                               і
Г--------------------------------------------------------------Дґ
і                                                               і
і ФОРТРАН      CALL OBIND(CURS,EMPNON,1,EMPNO,2,3)              і
і                                                               і
і              CALL OBINDN(CURS2,1,DEPTNO,2,3)                  і
і                                                               і
і КОБОЛ        CALL "OBINDN" USING CRC IN CURSOR-2,             і
і              ОNE,DEPTNO,DEPTNOL,ASC.                          і
і                                                               і
і              CALL "OBIND" USING CRC IN CURSOR-1,EMPNO-N,      і
і              EMPNO-N-L,EMPNO,FOUR,INTEGER.                    і
і                                                               і
і C            obind(curs,":ENAME",1,strings,-1,1);             і
і                                                               і
і              obindn(curs2,1,&deptno,2,3);                     і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                     OBNDRV  OBNDRN                            і
Г--------------------------------------------------------------Дґ
і                                                               і
і  CALL OBNDRV (cursor,sqlvar,sqlvl,provar,progvl,ftype[,scale] і
і              [,indp][,fmt[,fmtl]],fmtt]])                     і
і                                                               і
і  CALL OBNDRN (cursor,sqlvarnum,provar,progvl,ftype[,scale]    і
і              [,indp][,fmt[,fmtl]],fmtt]])                     і
і                                                               і
Г--------------------------------------------------------------Дґ
і                                                               і
і ФОРТРАН                                                       і
і    CALL OBNDRV(CURS(1,2),JOBNAM,,STRINGS(ENAMEL+2),JOBL,1)    і
і                                                               і
і КОБОЛ                                                         і
і    CALL "OBNDRV" USING C-RC IN CURSOR-1,EMPNO-N,              і
і    EMPNO-N-L,EMPNO,FOUR,PACKED,DEFLT,INDP,                    і
і    EMPNOF,SIX,PACKED.                                         і
і    CALL "OBNDRV"  USING C-RC IN CURSOR-1,ENAME-N,             і
і    ENAME-N-L,ENAME,ENAME-L,ASC,DEFLT,INDP,EMPNOF,ZERO,ZERO.   і
і                                                               і
і C  obndrv (curs,":ENAME",-1,strings,-1,1,-1,(short *)-1,      і
і      (char *)-1,0,0);                                         і
А--------------------------------------------------------------ДЩ


                            - 182 -

Ъ--------------------------------------------------------------Дї
і                          OBREAK                               і
Г--------------------------------------------------------------Дґ
і         CALL OBREAK (lda)                                     і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OBREAK(HDA(1))                         і
і                                                               і
і    КОБОЛ          CALL"OBREAK" USING LDA-RC.                  і
і                                                               і
і    C              (obreak(lda);                               і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                           OCAN                                і
Г--------------------------------------------------------------Дґ
і    CALL OCAN (lda)                                            і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OCAN(LDA(1))                           і
і                                                               і
і    КОБОЛ          CALL "OCAN" USING LDA-RC.                   і
і                                                               і
і    C              ocan(lda);                                  і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                          OCLOSE                               і
Г--------------------------------------------------------------Дґ
і    CALL OCLOSE (cursor)                                       і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OLOSE(CURS)                            і
і                                                               і
і    КОБОЛ          CALL "OCLOSE" USING C-RC IN CURSOR-1.       і
і                                                               і
і    C              oclose(curs);                               і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                        OCMN(не поддерживается)                і
Г--------------------------------------------------------------Дґ
і    CALL OCMN (lda,comment-,commentl-)                         і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                        OCOF                                   і
Г--------------------------------------------------------------Дґ
і    CALL OCOF (lda)                                            і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OCOF(LDAREA)                           і
і                                                               і
і    КОБОЛ          CALL "OCOF" USING LDA-RC.                   і
і                                                               і
і    C              if (ocof(curs[0]));                         і
А--------------------------------------------------------------ДЩ



                            - 183 -

Ъ--------------------------------------------------------------Дї
і                           OCOM                                і
Г--------------------------------------------------------------Дґ
і    CALL OCOM (lda)                                            і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OCOM(LDA)                              і
і                                                               і
і    КОБОЛ          CALL "OCOM" USING LDA-RC.                   і
і                                                               і
і    C              ocom(lda);                                  і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                           OCON                                і
Г--------------------------------------------------------------Дґ
і    CALL OCON (lda)                                            і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OCON(LDAREA)                           і
і                                                               і
і    КОБОЛ          CALL "OCON" USING LDA-RC.                   і
і                                                               і
і    C              ocon(lda);                                  і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                        ODEFIN                                 і
Г--------------------------------------------------------------Дґ
і CALL ODEFIN (cursor, pos, buffer, bufl, ftype [,scale] [,indp]і
і             [,fmt],fmt] [,fmtt ] ] [,retl] [,rcode] )         і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL ODEFIN(CURS(1),1,EMPNO,2,3)            і
і                                                               і
і    КОБОЛ          CALL "ODEFIN" USING C-RC IN CURSOR-1,ONE,   і
і                   EMPNO,FOUR,PACKED,DEFLT,INDP,EMPNOF,SIX.    і
і                                                               і
і    C              odefin(curs,1,&empno,2,3,-1,(short *)-1,    і
і                   (char *)-1,-1,-1,&rlen,&rcode);             і
А--------------------------------------------------------------ДЩ


Ъ--------------------------------------------------------------Дї
і     ODFINN (Новые программы должны использовать ODEFIN)       і
Г--------------------------------------------------------------Дґ
і CALL ODFINN (cursor, pos, buffer, bufl[,ftype][,rcode][,fdig])і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL ODFINN(CURS,1,EMPNO,4,3,RCODE,1)       і
і                                                               і
і    КОБОЛ          CALL "ODFINN" USING CRC IN CURSOR-2,ONE,    і
і                   DNAME,DNAME-L,ASC,RCODE,DEFLT.              і
і                                                               і
і    C              odfinn(curs[1],1,&empno,2,3,(short *)1,-1); і
А--------------------------------------------------------------ДЩ



                            - 184 -

Ъ--------------------------------------------------------------Дї
і                           ODSC                                і
Г--------------------------------------------------------------Дґ
і    CALL ODSC (cursor, position [,dbsize] [,fsize] [,rcode]    і
і              [,cbuf, [cbuf]] [,dbsize ])                      і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL ODSC(CURS(1),1,DEPTL)                  і
і                                                               і
і    КОБОЛ          CALL "ODSC" USING C-RC IN CURSOR-2,ONE,     і
і                   DNAME-SIZE.                                 і
і                                                               і
і    C       odsc(curs,1,&deptl,(short *)01,(short *)01,        і
і              (short *)01,(char *)-1,(short *)-1),(short *)-1);і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і     ODSRBN (Новые программы должны использовать ODSC)         і
Г--------------------------------------------------------------Дґ
і                                                               і
і    CALL ODSRBN (cursor,position [,dbsize][,dbtype][,fsize])   і
і                                                               і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL ODSRBN(CURS,1,ENAMEL,ENAMES,ENAMFZ)    і
і                                                               і
і    КОБОЛ          CALL "ODSRBN" USING CRC IN CURSOR-1,ONE,    і
і                   ENAME-SIZE,ENAME_TYPE,ENAME_FSIZE.          і
і                                                               і
і    C        odsrbn(curs[1],1,&enamel,(short *)1,(short *)-1); і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                           OERSMG                              і
Г--------------------------------------------------------------Дґ
і                                                               і
і    CALL OERMSG (rcode,msgbuf)                                 і
і                                                               і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OERMSG(CURS(1,1),ERMSG)                і
і                                                               і
і    КОБОЛ          CALL "OERMSG" USING ERR-RC,MSGBUF.          і
і                                                               і
і    C              oermsg(cur-0-,msg);                         і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                           OEXEC                               і
Г--------------------------------------------------------------Дґ
і                                                               і
і    CALL OEXEC (cursor)                                        і
і                                                               і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OEXEC(CURS)                            і
і                                                               і
і    КОБОЛ          CALL "OEXEC" USING C-RC IN CURSOR-1.        і
і                                                               і
і    C              oexec(curs);                                і
А--------------------------------------------------------------ДЩ


                            - 185 -

Ъ--------------------------------------------------------------Дї
і                           OFETCH                              і
Г--------------------------------------------------------------Дґ
і    CALL OFETCH (cursor)                                       і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OFETCH(CURS)                           і
і                                                               і
і    КОБОЛ          CALL "OFETCH" USING C-RC IN CURSOR-1.       і
і                                                               і
і    C              ofetch(curs);                               і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                           OLOGOF                              і
Г--------------------------------------------------------------Дґ
і    CALL OLOGOF (lda)                                          і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OLOGOF(LDA)                            і
і                                                               і
і    КОБОЛ          CALL "OLOGOF" USING LDA-RC.                 і
і                                                               і
і    C              ologof(lda);                                і
А--------------------------------------------------------------ДЩ


Ъ--------------------------------------------------------------Дї
і       OLOGON (Новые программы должны использовать OLON)       і
Г--------------------------------------------------------------Дґ
і    CALL OLOGON (lda [,areacount])                             і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OLOGON(LDAREA)                         і
і                                                               і
і    КОБОЛ          CALL "OLOGON" USING LDAREA,AREACOUNT.       і
і                                                               і
і    C              ologon(ldarea,2);                           і
А--------------------------------------------------------------ДЩ


Ъ--------------------------------------------------------------Дї
і                           OLON                                і
Г--------------------------------------------------------------Дґ
і    CALL OLON (lda [,uid, uidlen] [,psw, pswl] [,0] )          і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OLON(LDA(1),UIDPSW,,,,0)               і
і                                                               і
і    КОБОЛ          CALL "OLON" USING LDA-RC,USER-ID,USER-ID-L, і
і                        PSW,PSWLEN,ZERO.                       і
і                                                               і
і    C              olon(lda,uid,-1,(char *)-1,-1,0);           і
А--------------------------------------------------------------ДЩ



                            - 186 -

Ъ--------------------------------------------------------------Дї
і                           ONAME                               і
Г--------------------------------------------------------------Дґ
і    CALL ONAME (cursor, position, tbuf, tbufl, cbuf, cbufl)    і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL ONAME(CURS1,2,TABLE,TABLEL,COL,COLL)   і
і                                                               і
і    КОБОЛ          CALL "ONAME" USING CURS4,SELPOS,            і
і                        TABLE,TABLEL,COL,COLL                  і
і                                                               і
і    C              oopt(curs,2,4);                             і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                   ORES (Не поддерживается)                    і
Г--------------------------------------------------------------Дґ
і    CALL ORES (cursor)                                         і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                           ORLON                               і
Г--------------------------------------------------------------Дґ
і    CALL ORLON (lda ,hda [,uid, uidlen]                        і
і                [,psw, pswl] [,audit_flag] )                   і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL ORLON(LDA(1),UIDPSW,,,,0)              і
і                                                               і
і    КОБОЛ          CALL "ORLON" USING LDA-RC,USER-ID,USER-ID-L,і
і                        PSW,PSWLEN,ZERO.                       і
і                                                               і
і    C              orlon(lda,uid,-1,(char *)-1,-1,0);          і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і                           OROL                                і
Г--------------------------------------------------------------Дґ
і    CALL OROL (lda)                                            і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OROL(LDA)                              і
і                                                               і
і    КОБОЛ          CALL "OROL" USING LDA-RC.                   і
і                                                               і
і    C              orol(lda);                                  і
А--------------------------------------------------------------ДЩ

Ъ--------------------------------------------------------------Дї
і       OSQL (Новые программы должны использовать OSQL3)        і
Г--------------------------------------------------------------Дґ
і    CALL OSQL (cursor,sqlstatement [,sqllen])                  і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OSQL(CURS,SQLSTM,SQLSTL)               і
і                                                               і
і    КОБОЛ          CALL "OSQL" USING C-RC IN CURSOR-1,         і
і                   SQL-SELEMP,SQL-SELEMP-L.                    і
і                                                               і
і    C       osql(curs[1],"SELECT NVL(MAX(EMPNO)) FROM EMP",-1);і
А--------------------------------------------------------------ДЩ


                            - 187 -

Ъ--------------------------------------------------------------Дї
і                           OSQL3                               і
Г--------------------------------------------------------------Дґ
і    CALL OSQL3 (cursor,sqlstatement [,sqllen] )                і
Г--------------------------------------------------------------Дґ
і                                                               і
і    ФОРТРАН        CALL OSQL3(CURS(1),SQLSTM)                  і
і                                                               і
і    КОБОЛ          CALL "OSQL3" USING C-RC IN CURSOR-1,        і
і                   SQL-SELMAX,SQL-SELMA-L.                     і
і                                                               і
і    C         osql3(osql(curs,"SELECT  ENAME,JOB FROM EMP",-1);і
А--------------------------------------------------------------

KOAP Open Portal 2000



Яндекс цитирования