Язык программирования баз данных Informix-4GL

2. Работа с базой данных

2.1. Общие принципы работы с SQL в Informix-4GL

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

2.3. Динамический SQL

2.4. Использование курсоров в операциях модификации данных

2. Работа с базой данных

2.1. Общие принципы работы с SQL в Informix-4GL

В Informix-4GL операторы SQL встраиваются в исходную программу так, как если они были бы выполняемыми операторами ее основного языка.

Выполнение оператора SQL фактически является вызовом сервера базы данных. Информация должна передаваться от программы-клиента программе-серверу и возвращаться обратно. Часть этих взаимодействий осуществляется через так называемые главные переменные, посредством которых передаются входные данные для SQL-описаний и возвращаются результаты запроса. Ни при объявлении, ни при использовании внутри SQL-описаний главные переменные в языке Informix-4GL никак не выделяются и не отличаются от обычных переменных языка Informix-4GL. SQL-описания в программе на языке Informix-4GL так же, как и главные переменные, никак не выделяются.

Для обработки ошибок, связанных с выполнением SQL-запросов в программе на языке Informix-4GL, доступна структура SQLCA, описанная в прил. А [5]. Доступ к отдельным полям структуры выполняется обычным образом (sqlca.sqlcode, sqlca.sqlerrd[3] и т.д.). Переменная sqlca.sqlcode доступна также в 4GL-программе под именем STATUS, если проверка значения STATUS выполняется непосредственно после SQL-запроса. При этом STATUS устанавливается в 0, если оператор выполнен правильно, в отрицательное значение в случае ошибки и равен NOTFOUND (100), если операторы Select или Fetch не нашли никаких строк данных. Если переменная STATUS проверяется после 4GL-оператора, она содержит код завершения последнего оператора языка Informix-4GL.

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

Единственным отличием приведенных выше SQL-запросов от интерактивных SQL-операторов [7,8] является наличие спецификатора Into, задающего главные переменные, которые используются как получатели данных и в условии Where. Если записанный выше оператор Select производит более одной строки данных, то сервер базы данных возвратит код ошибки. В SQL-запросе не требуется, чтобы главная переменная, в которую помещается значение, имела бы в точности такой же тип данных, что и в таблице. Сервер делает все возможное для преобразования данных из столбцов в форму, используемую переменными-получателями этих данных.

Как уже отмечалось ранее, Informix-4GL поддерживает NULL-значения переменных. Их использование показано на примере.

Замечание. В программе на Informix-4gl оператор Database может преследовать две цели; одна - процедурная, другая - непроцедурная. Этот оператор делает базу данных текущей (процедурная цель) и говорит компилятору, где найти информацию о составе столбцов таблиц для использования при исполнении конструкции LIKE и нотации <имя таблицы>.* (непроцедурная цель). Если указанных конструкций в программе нет, то оператор Database может появиться с процедурной целью в любом месте программы, с непроцедурной целью оператор Database должен появиться за пределами программы и предшествовать блоку GLOBALS с тем, чтобы компилятор при обработке конструкций LIKE и <имя таблицы>.* имел информацию о составе таблиц базы данных на этапе трансляции.

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

Обработка многострочного запроса осуществляется в два этапа. Сначала программа дает старт запросу, после которого не возвращаются никакие данные. Затем программа запрашивает строки данных по одной на каждое требование. Эти операции выполняются с помощью специального объекта данных, называемого курсором. Курсор является структурой данных, представляющей текущее состояние запроса. Основная последовательность программных операций с курсором выглядит следующим образом:

  1. Программа объявляет курсор и ассоциированный с ним оператор Select. Это приводит лишь к выделению памяти для хранения курсора.
  2. Программа открывает этот курсор, что приводит к началу выполнения ассоциированного оператора Select.
  3. Программа считывает очередную строку данных в главные переменные и обрабатывает их.
  4. Программа закрывает курсор после прочтения последней строки.

Эти операции выполняются с помощью операторов SQL Declare, Open, Fetch, Close, Foreach.

Множество строк, возвращаемое предложением Select, называется активным множеством. В любой момент времени 4GL-программа может работать только с одной строкой - это текущая строка, на которую указывает курсор. Курсор может находиться в одном из двух состояний: открытом и закрытом. Когда курсор открыт, он связан с открытым множеством и может указывать либо на текущую строку, либо между строк, либо перед первой строкой, либо после последней строки. Если курсор находится в закрытом состоянии, он больше не связан с активным множеством, хотя и остается связанным с оператором Select.

Объявление курсора

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

Оператор Declare объявляет курсор, задавая его имя, специфицируя его использование и связывая с курсором оператор Select. Оператор Declare не является активным оператором, он только устанавливает свойства курсора и выделяет для него память. Область действия курсора - от точки его объявления до конца файла. Примеры объявления курсора приведены ниже.

Открытие и закрытие курсора

Когда программа готова к использованию курсора, она его открывает (активизирует) оператором Open. По оператору Open ассоциированный с курсором оператор Select передается серверу базы данных, который начинает поиск соответствующих строк. Сервер обрабатывает этот запрос до момента нахождения или конструирования первой строки результата. Он реально не возвращает эту строку данных, но устанавливает код возврата в переменную STATUS (sqlca.sqlcode). Если переменная STATUS равен нулю, оператор синтаксически правилен и курсор готов к использованию. Оператор Close, напротив, переводит курсор в закрытое состояние и освобождает активное множество.

Курсорная выборка строк

Оператор Fetch служит для выборки строки результата: он именует курсор, переводит курсор к определенной строке активного множества и выбирает значения из этой строки. Оператор Fetch может также задавать имена главных переменных для приема данных в спецификаторе Into, который нужно включать либо в оператор Select, либо в оператор Fetch, но не в оба сразу. Вторая форма имеет то преимущество, что разные строки могут быть считаны в разные переменные. Если оператор Fetch перемещает курсор перед первой строкой или после последней строки, в переменную STATUS (sqlca.sqlcode) устанавливается код возврата NOTFOUND (100).

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

При необходимости выполнить группу действий для каждой строки результата (режим Row-by-Row) можно воспользоваться оператором FOREACH ... END FOREACH. При его использовании отпадает необходимость в ручном открытии и закрытии курсора.

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

Next

Выбор следующей строки активного множества.

Previous

Выбор предыдущей строки активного множества.

First

Выбор первой строки активного множества.

Last

Выбор последней строки активного множества.

Current

Выбор текущей строки активного множества (той, что была прочитана ранее).

Relative

Выбор n-й строки относительно текущей позиции курсора из активного множества.

Absolute

Выбор n-й строки активного множества (нумерация с 1).

Ниже приведены примеры записи оператора Fetch c различными значениями спецификатора перемещения курсора.

Приведенный ниже пример иллюстрирует использование скроллирующего курсора при выборе каждой второй строки из некоторой группы.

Ниже приведен фрагмент программы для поиска и отображения строк таблицы.

2.3. Динамический SQL

В ряде приложений возникает необходимость в динамическом формировании SQL-операторов по ходу выполнения программы. Этого могут потребовать:

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

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

  • программа собирает текст оператора SQL в виде символьной строки, хранящейся в программной переменной; в общем случае это может быть не один, а несколько операторов SQL, разделенных точкой с запятой;
  • программа выполняет оператор Prepare, который обращается к серверу баз данных на предмет изучения текста оператора и подготовки его к выполнению;
  • программа использует оператор Execute для выполнения подготовленного оператора.

Подготовка операторов

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

  • в динамический оператор Select нельзя включать спецификатор Into, в котором используются главные переменные;
  • в любом месте, где главная переменная могла бы появиться в выражении SQL-оператора, ей соответствует знак вопроса.

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

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

Значения главных переменных, используемые при формировании SQL-оператора, могут быть получены из пользовательского ввода и присоединены к текстовой строке на этапе формирования SQL-оператора. В этом случае отпадает необходимость использования знака "?".

Указатели позиции "?" не могут быть использованы вместо идентификаторов SQL таких, как имя базы данных, имя таблицы или столбца: эти идентификаторы должны указываться в тексте оператора при его подготовке. Если эти идентификаторы не известны во время написания программы, они могут быть получены из пользовательского ввода, аналогично предыдущему примеру.

Замечаниe. Запрещенными для динамического формирования являются операторы, непосредственно связанные с динамическим SQL (Prepare, Execute), операторы управления курсором (Declare, Open, Fetch, ...), а также операторы работы на уровне базы данных (Create database, Database, ...).

Выполнение подготовленного SQL-оператора

Подготовленный по оператору Prepare динамический оператор (группу операторов) можно многократно выполнять. С помощью оператора Execute выполняются операторы, отличные от операторов Select, а также операторы Select, которые возвращают в качестве результата одну строку. Если оператор Select возвращает более одной строки, динамический оператор Select выполняется не с помощью оператора Execute, а подключается к курсору и в дальнейшем используется обычным образом с помощью курсорных средств. В обоих случаях при выполнении динамического оператора с помощью спецификатора Using ему передаются главные переменные, участвующие в выражениях и принимающие возвращаемые значения и, по сути, играющие роль фактических параметров .

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

  1. Символьная строка, задающая оператор Select, помещается в программную переменную. Она содержит два заполнителя, отмеченных знаком вопроса.
  2. Оператор PREPARE преобразует символьную строку в структуру данных с именем q_orders, которая может быть выполнена.
  3. Объявляется курсор с именем cu_orders и связывается с именем подготовленного оператора.
  4. Вводятся необходимые параметры для SQL-оператора.
  5. При открытии курсора выполняется подготовленный оператор. Спецификатор Using в операторе Open указывает имена двух главных переменных, содержимое которых заменяет знаки вопроса, указанные в исходном операторе.
  6. Первая строка данных выбирается с помощью открытого курсора. Спецификатор Into оператора Fetch специфицирует главные переменные, которые должны принимать значения столбцов строки, выбранной по курсору.

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

Для простых операторов, не требующих курсора или главных переменных, можно объединить действия операторов Prepare, Execute, Free в одной операции. Оператор Execute Immediate получает строку символов, подготавливает ее, выполняет и освобождает память.

2.4. Использование курсоров в операциях модификации данных

Для повышения эффективности выполнении операций Delete, Update и Insert можно использовать специальные формы курсоров.

Использование курсоров для удаления текущей строки

Для удаления строки, которая была выбрана по курсору последней, необходимо использовать оператор Delete совместно с курсором. Для этого следует включить конструкцию FOR UPDATE в оператор Declare для последовательного курсора и конструкцию Where Current of в последующий оператор Delete.

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

Использование курсоров для корректировки текущей строки

Для корректировки строки, которая была выбрана по курсору последней, необходимо использовать оператор Update совместно с курсором. Для этого следует включить конструкцию FOR UPDATE в оператор Declare для последовательного курсора и конструкцию Where Current of в последующий оператор Update.

Перечисление в конструкции FOR UPDATE оператора Declare имен столбцов указывает на недопустимость корректировки столбцов, имена которых отличны от названных. Любая попытка корректировки необозначенных столбцов вызовет ошибку.

В нижеприведенном фрагменте программы из столбца Datcol таблицы Target удаляются ошибочно занесенные NULL-значения, а в столбец Serial заносятся неповторяющиеся значения целого типа.

Использование курсоров для вставки

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

PUT

Устанавливает буфер ввода для курсора оператора Insert. PUT сохраняет строку в буфере оператора Insert для последующего ввода в базу данных. Когда буфер заполнен целиком, он автоматически записывается в требуемую таблицу как блок.

FLUSH

Принудительно переносит строки из буфера в таблицу базы данных.

Приведенный ниже фрагмент программы заполняет базу данных с использованием аппарата курсора. Используемая в тексте функция next_cust возвращает либо информацию о новом клиенте, либо Null-значение, сигнализирующее об окончании ввода. Если эта функция возвращает значение, отличное от NULL-значения, оператор PUT посылает полученные данные в буфер строк. Когда буфер заполняется, строки, которые он содержит, автоматически пересылаются на сервер. Цикл нормально завершается, когда next_cust перестает возвращать данные.

Замечание. Использование курсорных средств и операторов PUT, FLUSH взамен оператора INPUT приводит к более быстрому исполнению программы.