|
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);і
А--------------------------------------------------------------
|
|