Главная » SQL, Базы данных » ВНЕДРЕНИЕ ОПЕРАТОРОВ  SQL

0

В большинстве продуктов SQL операторы языка SQL могут выполняться как непосредственно (т.е. интерактивно, с подключенного терминала), так и в виде части  прикладной программы (т.е. операторы SQL могут быть внедренными, а значит, могут смешиваться с операторами базового языка этой программы). Приложения, использующие внедренные операторы SQL, могут быть написаны на многих базовых языках; стандарт SQL включает поддержку для Ada, С, COBOL, Fortran, Java, M (прежде известного как  MUMPS), Pascal и PL/I. Рассмотрим особенности технологии внедрения операторов SQL более подробно.

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

Прежде чем начать обсуждение конкретных внедряемых операторов SQL, необходимо обсудить некоторые детали. Большинство из них иллюстрируется фрагментом программы, представленным на рис. 4.3. (Для закрепления наших представлений будем считать, что базовым языком является PL/I. Большинство приводимых примеров транслируется на другие базовые языки лишь с незначительными изменениями.)

Рассмотрим этот фрагмент программы.

1.  Внедренные операторы SQL предваряются инструкцией EXEC SQL, так что их лег ко отличить от других операторов базового языка, и заканчиваются специальным завершающим символом (для языка PL/I таковым является точка с запятой "; ").

2.  Выполняемый оператор SQL (далее и до конца этого раздела уточняющее слово вне дренный обычно не будет применяться) может быть в программе везде, где могут находиться выполняемые операторы базового языка. Обратите внимание на уточ няющее слово выполняемый: в отличие от интерактивного режима использования языка SQL, режим внедрения операторов SQL подразумевает включение в про грамму отдельных операторов SQL, которые являются чисто декларативными, а не выполняемыми. Например, оператор DECLARE  CURSOR — это не выполняемый оператор (подробности приводятся в разделе "Операции, в которых используются курсоры"); таковыми не являются и операторы BEGIN и END DECLARE SECTION (см. п. 5 этого списка), а также оператор WHENEVER (СМ. П. 9).

EXEC SQL BEGIN DECLARE SECTION ; DCL SQLSTATE CHAR(5) ; DCL P# CHAR(6) ; DCL WEIGHT FIXED DECIMAL(5,1) ;

EXEC SQL END DECLARE SECTION ;

P# = ‘ P2 ‘ ;     /* Рассматривается в качестве примера */ EXEC SQL SELECT P.WEIGHT

INTO :WEIGHT FROM P

WHERE P.P# = P# ( :P# ) ; IF SQLSTATE = ‘00000’ THEN …

;                                        /* WEIGHT значение, полученное путем выборки */ ELSE … ;                                        /* Возникло некоторое исключение */

Рис. 4.3. Фрагмент программы на языке PL/I с внедренными операторами языка SQL

3.  Операторы SQL могут включать ссылки на базовые переменные (т.е. переменные базового языка). Подобные ссылки должны иметь префикс в виде двоеточия, позволяющий отличить их от имен столбцов таблиц  SQL.  Базовые переменные могут применяться во внедренных операторах  SQL везде, где в интерактивном языке SQL могут использоваться литералы. Они могут также находиться в предложении INTO операторов SELECT (см.  п. 4) и FETCH (подробности — в разделе "Операции, в которых  используются курсоры"), определяющем результирующие переменные для размещения результатов выборки данных.

4.  Обратите внимание на конструкцию INTO оператора SELECT, представленного на рис. 4.3. Назначение этой конструкции (как только что отмечалось) — указать ре зультирующие (целевые) переменные, в которых будут возвращены выбранные зна чения. Каждая /-я целевая переменная, указанная в предложении INTO, соответству ет /-му извлекаемому значению, указанному в списке выборки предложения SELECT.

5.  Все базовые переменные, на которые ссылаются внедренные операторы SQL, долж ны быть определены в разделе объявлений внедренного языка SQL, который ограни чивается  операторами  BEGIN   DECLARE   SECTION И  END   DECLARE SECTION

(в PL/I для этого используется операторDCL).

6.  Каждая программа, содержащая внедренные операторы SQL, должна включать ба зовую переменную с именем SQLSTATE. После выполнения любого присутствую щего в программе оператора SQL в эту переменную возвращается код состояния. В частности, код состояния 00000 означает, что оператор был выполнен успешно, а код состояния 02000 — что оператор был выполнен, но никаких удовлетворяю щих запросу данных найдено не было (другие значения указаны в [4.23]). Таким образом, выполнение в программе каждого оператора SQL должно завершаться проверкой значения переменной SQLSTATE и, если это значение будет отличаться от ожидаемого, должны предприниматься соответствующие действия. На практи ке, однако, такая проверка обычно выполняется неявно (см. п. 9).

7.  Каждая переменная базового языка должна иметь тип данных, соответствующий значениям, для хранения которых эта переменная используется. В частности, базовая переменная, используемая в качестве целевой (например, для хранения результатов операции SELECT), должна иметь тип данных, совместимый с типом выражения, значение которого присваивается этой целевой базовой переменной. Аналогично, если базовая переменная служит источником (например, для опера ции INSERT), она должна иметь тип данных, совместимый с типом SQL того столбца, которому присваивается значение из этого источника. Но эта тема явля ется гораздо более сложной по сравнению со сведениями, приведенными в данной главе, поэтому она здесь не рассматривается (по крайней мере, достаточно под робно), а ее дальнейшее обсуждение будет продолжено в главе 5, раздел 5.7.

8.  Базовые переменные для столбцов таблиц SQL могут иметь те же имена, что и имена соответствующих столбцов.

9.  Как уже упоминалось, выполнение каждого оператора SQL, в принципе, должно сопровождаться проверкой значения, возвращаемого в переменной SQLSTATE. Для упрощения этого процесса предназначен оператор WHENEVER, который имеет следующий синтаксис.

EXEC SQL WHENEVER <condition> <action> }’,

Здесь параметр <condi tion> (условие) может принимать значение NOT FOUND (данные  не  найдены),  SQLWARNING   (предупреждающее   сообщение  SQL)  и SQLEXCEPTION (исключительная ситуация SQL) (другие условия включают определенные значения SQLSTATE и  фиксируют нарушения заданных ограничений целостности), а параметр  <action>— это либо оператор CONTINUE (продолжить), либо оператор GO TO (перейти к метке). Оператор WHENEVER не является выполняемым; это просто директива для компилятора SQL. Наличие в программе выражения  "WHENEVER  <condition>  GO  TO  <label>"  приведет  к  тому,  что компилятор поместит оператор "IF <condition> GO TO <label>  END IF" после каждого встретившегося ему выполняемого оператора SQL. Однако, встретив  выражение  "WHENEVER  <condition>  CONTINUE",  компилятор  SQL  не вставляет в программу никаких операторов, и следовательно, программист должен будет вставить требуемые операторы вручную. Условия NOT FOUND, SQLWARNING и SQLEXCEPTION определены, как описано ниже.

■     NOT FOUND показывает, что не найдены данные, соответствующие оператору;

значение SQLSTATE =  02ххх;

■     SQLWARNING  означает,  что  возникла  незначительная  ошибка;   значение

SQLSTATE = Olxxx;

■     SQLEXCEPTION означает, что возникла серьезная ошибка (исключительная си туация); значения SQLSTATE приведены в [4.23].

Каждый оператор WHENEVER (для определенного условия), встреченный компилятором при последовательном просмотре текста программы, отменяет предыдущий (для этого условия).

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

Итак, для предварительного обсуждения этого достаточно. В остальной части этого раздела главным образом рассматриваются операторы манипулирования данными. Как уже отмечалось, большинство из них можно использовать  практически в неизменном виде (т.е. лишь с незначительными изменениями в синтаксисе). Однако операции выборки требуют отдельного описания. Проблема состоит в том, что такие операторы в общем случае выбирают не одну, а множество строк, в то время как процедурные базовые языки обычно не приспособлены для выборки больше одной строки за одно обращение. Следовательно, необходимо создать своего рода "мост" между предусмотренными в языке SQL средствами выборки, позволяющими получать одновременно множество строк, и применяемыми в базовом языке средствами обработки, допускающими одновременное использование только одной строки. В качестве подобного "моста" используются курсоры. Курсор представляет собой своего рода логический указатель, который может использоваться в приложении для перемещения по набору строк, указывая поочередно на каждую из них и таким образом обеспечивая возможность адресации этих строк — по одной за один раз. Однако временно отложим подробное обсуждение курсоров (до подраздела "Операции, в которых используются курсоры") и рассмотрим сначала такие операторы, для которых курсоры не требуются.

Операции, в которых не используются курсоры

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

■  Однострочный оператор SELECT.

■   INSERT.

■   UPDATE (кроме формы CURRENT — см. следующий подраздел).

■  DELETE (также кроме формы CURRENT — см. следующий подраздел).

Рассмотрим примеры каждого из этих операторов.

Однострочный оператор SELECT. Получить статус и название города для поставщика, номер которого задан в базовой переменной GlVENS#.

EXEC SQL SELECT STATUS, CITY INTO :RANK, :TOWN FROM S WHERE S# = S# ( :GIVENS# )

;

Термин однострочный оператор SELECT используется для обозначения выражения SELECT, значением которого будет таблица, содержащая не больше одной строки. В данном примере, если в таблице S существует одна и только одна строка, отвечающая заданному условию в конструкции WHERE, значения столбцов STATUS и CITY из этой строки в соответствии  с  запросом будут присвоены базовым переменным RANK и CITY, а переменной SQLSTATE будет присвоено значение 00000. Если в таблице S  нет ни одной строки, отвечающей заданному условию WHERE, переменной  SQLSTATE будет присвоено значение 02000. Если же таких строк окажется больше одной, будет зафиксирована ошибка и переменная  SQLSTATE будет содержать ее код.

■  Оператор INSERT. Вставить в таблицу Р сведения о новой детали (номер детали, ее название и вес задаются содержимым базовых переменных Р#, PNAME, PWT, соответственно; цвет детали и город неизвестны).

EXEC SQL INSERT

INTO P ( P#, PNAME, WEIGHT ) VALUES ( :P#, :PNAME, :PWT )

;

Столбцам COLOR и CITY вновь добавляемой строки таблицы будут присвоены соответствующие значения, применяемые по умолчанию. Подробнее об этом речь пойдет в разделе 6.6 главы 6. Следует отметить, что по причинам, анализ которых выходит за рамки данной книги, применяемое по умолчанию значение для столбца, который имеет некоторый тип, определяемый пользователем, обязательно должно быть неопределенным (NULL). (Подробное обсуждение темы, касающейся неопределенных значений, откладывается до главы 19; однако нам неизбежно придется время от времени возвращаться к этому вопросу.)

Оператор DELETE. Удалить сведения обо всех поставках для поставщиков из города, название которого помещено в базовую переменную CITY.

EXEC SQL DELETE FROM  SP

WHERE :CITY =

( SELECT CITY FROM   S

WHERE S.S# = SP.S#

) ;

И снова, если нет строк, удовлетворяющих условию WHERE, переменной SQLSTATE присваивается значение 02000. Также обратите внимание на вложенный подзапрос (на этот раз в предложении WHERE).

■     Оператор UPDATE. Увеличить статус всех поставщиков из Лондона на значение,

помещенное в базовую переменную RAISE.

EXEC SQL UPDATE S

SET   STATUS = STATUS +

:RAISE WHERE CITY = ‘London1

;

Если в таблице поставщиков не будет найдено строк, удовлетворяющих условию

WHERE, система присвоит переменной SQLSTATE значение 02000.

Операции, в которых используются курсоры

Теперь перейдем к вопросу о выборках на уровне множеств, т.е. о выборках не одной строки, как это было в случае однострочного оператора SELECT, а  множества с произвольным количеством строк. Как указывалось ранее, в этой ситуации потребуется поочередный доступ к строкам выбранного множества, а механизмом такого доступа будет курсор. На рис. 4.4 этот процесс схематически проиллюстрирован на примере выборки информации о поставщиках (столбцы s#, SNAME и STATUS) для всех поставщиков из города, название которого задается в базовой переменной У.

EXEC SQL DECLARE X CURSOR FOR     /* Определить курсор   */ SELECT S.S#, S.SNAME, S.STATUS FROM   S

WHERE  S.CITY = :Y ORDER  BY Si ASC ;

EXEC SQL OPEN X ;                                                                                     /* Выполнить запрос    */ DO <для всех строк S, доступных через Х> ;

EXEC SQL FETCH X INTO :S#, :SNAME, :STATUS ;

/* Получить данные о

следующем поставщике  */

END ;

EXEC SQL CLOSE X ;                                                                                     /* Перевести курсор X в

неактивное состояние  */

Рис. 4.4. Выборка нескольких строк

Пояснение. Оператор DECLARE X CURSOR. . . определяет курсор х,  связанный с табличным  выражением  (т.е.  выражением,  которое  возвращает  таблицу).  Табличное выражение определяется оператором SELECT, который является частью всего выражения

DECLARE,  но  не  вычисляется  в  этом  месте  программы,  поскольку  оператор DECLARE CURSOR— чисто декларативный. Табличное выражение вычисляется только при открытии курсора (оператор OPEN X). Далее для выборки строк из результирующего множества, по одной за один раз, используется  оператор  FETCH X INTO. . ., присваивающий извлеченные значения базовым переменным в соответствии со спецификациями в конструкции INTO. (Для простоты базовым переменным присвоены имена, совпадающие с именами соответствующих столбцов таблицы базы данных. Обратите внимание, что в операторе SELECT при определении курсора не задается собственная конструкция INTO.) Поскольку в результирующем наборе потенциально присутствует большое количество строк, оператор FETCH обычно вызывается в цикле. Цикл будет повторяться до тех пор, пока не закончатся строки в результирующем наборе. После выхода из цикла курсор х закрывается (оператор CLOSE X).

А теперь рассмотрим курсоры и операции с ними более подробно. Курсор определяется с помощью оператора DECLARE CURSOR, который имеет следующий общий вид.

EXEC SQL DECLARE <cursor name> CURSOR FOR <table exp> [ <ordering> ] ;

Для краткости несколько необязательных спецификаций в этом определении не указаны. Здесь параметр <cursor name> — это имя определяемого курсора. Необязательный параметр определения сортировки результата выборки <ordering> имеет следующий формат.

ORDER BY  <order item  commalist>

Здесь параметр <order item commalist> — разделенный запятыми список  элементов <order i tem>, по которым должно быть выполнено упорядочение извлекаемых строк. Список должен содержать не меньше одного элемента < order i tem>, а в каждом элементе списка должно содержаться имя столбца (заметьте, неуточненное)4, после которого может следовать необязательное служебное слово ASC (по возрастанию) или DESC (по убыванию). При отсутствии служебного слова по умолчанию принимается порядок по возрастанию (ASC). Если конструкция ORDER BY не определена, то принцип упорядочения определяется системой. (Фактически, последнее замечание остается в силе, если даже определена конструкция ORDER BY, по крайней мере, когда речь идет о строках с одним и тем же значением для указанного списка< order item commalist>.)

Примечание. Дадим определение удобному термину разделенный запятыми список элементов (commalist). Пусть <xyz> обозначает произвольную синтаксическую категорию (т.е. то, что находится слева от некоторого правила вывода в нотации BNF). Тогда выражение <xyz commalist> (или <разделенный запятыми список xyz>) обозначает последовательность от нуля и больше элементов <xyz>, в которой каждая пара элементов <xyz> разделена

4  Фактически, имя столбца может быть уточнено, если заданное табличное выражение <table  exp> соответствует довольно сложному набору правил. Эти правила были впервые введены в  стандарте SQL: 1999, в котором также регламентированы правила, согласно которым элемент  <order item> может иногда определять либо вычислительное выражение, например, ORDER BY  A+B, либо имя столбца, который входит в состав таблицы результата, например, SELECT CITY FROM S ORDER BY STATUS. Изложение подробных сведений об этих правилах выходит за рамки настоящей книги.

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

Как утверждалось ранее, оператор DECLARE CURSOR — декларативный, а не выполняемый. Он предназначен для объявления курсора с определенным  именем, для которого предусмотрено табличное выражение и с которым постоянно связан тип упорядочения. Табличное выражение может включать ссылки на базовые переменные. Программа может содержать любое количество  операторов DECLARE CURSOR, каждый из которых должен быть, конечно, предназначен для определения разных курсоров.

Для работы с курсорами существует три выполняемых оператора: OPEN, FETCH И

CLOSE.

■     Оператор OPEN имеет следующий формат.

EXEC SQL OPEN <cursor name>;

Он предназначен для открытия или активизации указанного курсора (который в данный момент не должен быть открыт). В результате его выполнения вычисляется связанное с этим курсором табличное выражение (причем для всех базовых переменных, упоминаемых в этом выражении,  используются текущие значения). В результате идентифицируется  определенное множество строк, которое становится текущим активным набором для данного курсора. Курсор также устанавливает исходную позицию в этом активном наборе, а именно — позицию перед его первой  строкой. Следует отметить, что активные наборы всегда рассматриваются  как  упорядоченные  (см.  приведенное  выше  описание  конструкции ORDER BY), а значит, и понятие позиции имеет для них смысл5.

■    Оператор FETCH имеет следующий формат.

EXEC SQL FETCH <cursor name>

INTO <host variable reference commalist> ;

Здесь  параметр  <host  variable  reference  commalist>—разделенный   запятыми список ссылок на базовые переменные. Этот оператор служит для перемещения позиции указанного курсора (который должен быть уже открыт) к следующей строке   в   его   активном   наборе   с   последующим   присваиванием   значений столбцов этой строки базовым переменным,  указанным в предложении INTO. Если  после очередного  вызова  оператора  FETCH  на  выполнение  следующая строка   отсутствует,   то   выборка   данных   не   производится   и   переменной SQLSTATE присваивается значение 02 000.

■    Оператор CLOSE имеет следующий формат.

EXEC  SQL CLOSE  <cursor name>   ;

5 Сами по себе множества, конечно, не являются упорядоченными (глава 6), так что "активный набор" — это на самом деле не множество как таковое. Его лучше представлять в виде упорядоченного списка или массива (строк).

Он служит для закрытия (деактивизации) указанного курсора (который должен быть в данный момент открытым). После его выполнения с курсором уже не будет связан активный набор. Однако в дальнейшем курсор вновь может быть открыт; при этом он снова получит активный набор — возможно, уже не такой, как раньше (в частности, если значения указанных в объявлении курсора базовых переменных к текущему моменту были изменены). Следует отметить, что изменение этих переменных при открытом курсоре не оказывает влияния на его активный набор.

Есть еще два оператора, в которых могут использоваться ссылки на курсоры, — это варианты операторов UPDATE и DELETE С конструкцией CURRENT. ЕСЛИ курсор (скажем, х) в данный момент позиционирован на определенную строку, то можно обновить или удалить эту "текущую строку курсора х", т.е. строку, на которую в данный момент позиционирован курсор х, например, как показано ниже.

EXEC SQL UPDATE S

SET STATUS = STATUS +

:RAISE WHERE CURRENT OF X

;

Выражения CURRENT операторов DELETE и UPDATE будут недопустимыми, если табличное выражение < table exp> в объявлении курсора определено с участием необновляемого представления, созданного с помощью оператора CREATE VIEW (подробности приведены в главе 10, раздел 10.6).

Динамический язык SQL и интерфейс SQL/CLI

В предыдущем разделе по умолчанию предполагалось, что данная конкретная  программа (включая операторы SQL и все операторы базового языка) может быть полностью откомпилирована "заблаговременно" (т.е. до наступления этапа прогона) в том виде, в каком она реализуется на данный момент. Однако применительно к некоторым приложениям соблюдение такого условия нельзя гарантировать. Например, рассмотрим оперативное приложение. (Напомним, что, как отмечалось в главе 1, оперативными называются приложения, которые предоставляют пользователю доступ к базе данных с некоторого интерактивного терминала или подобного ему устройства.) Как правило, в этом приложении должны выполняться примерно такие действия, как показано ниже.

1.           Принять с терминала команду пользователя.

2.           Проанализировать поступившую команду.

3.           Сгенерировать соответствующие операторы SQL для обращения к базе данных.

4.           Возвратить сообщение и (или) полученные результаты на терминал.

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

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

Динамический язык SQL

Средства динамического языка SQL — это часть средств поддержки внедрения языка SQL. Они состоят из множества динамических операторов (компиляция самих этих операторов осуществляется заблаговременно), назначение которых состоит именно в том, чтобы обеспечивать поддержку трансляции и выполнения обычных операторов SQL, создаваемых на этапе прогона программы. Таким образом, существуют два основных динамических оператора SQL — PREPARE  (Подготовить — по сути, компилировать) и EXECUTE (Выполнить). Их использование проиллюстрировано на следующем (нереальном по своей простоте, но достаточно точном) примере на языке PL/I.

DCL SQLSOURCE CHAR VARYING (65000) ;

SQLSOURCE = ‘DELETE FROM SP WHERE QTY < QTY ( 3 00

)’ ; EXEC SQL PREPARE SQLPREPPED FROM :SQLSOURCE ; EXEC SQL EXECUTE SQLPREPPED ;

Пояснения

1.  Имя SQLSOURCE идентифицирует переменную языка PL/I типа символьной стро ки переменной длины, в которой на этапе прогона программа определенным об разом подготавливает исходную форму (т.е. представление в виде символьной строки) некоторого оператора SQL, в нашем конкретном примере — оператора DELETE.

2.  Имя SQLPREPPED, напротив, идентифицирует переменную среды SQL, а не базового языка PL/I, которая будет (в принципе) использоваться для хранения компилиро ванной формы оператора SQL (исходная форма которого представлена в перемен ной SQLSOURCE). Конечно, имена, подобные SQLSOURCE И SQLPREPPED, МОЖНО выбирать произвольно.

3.  С помощью оператора присваивания SQLSOURCE =…; на языке PL/I перемен ной SQLSOURCE присваивается исходная форма оператора SQL DELETE. Конечно, на практике процесс формирования такого исходного оператора будет значитель но сложнее и, возможно, в нем будут использоваться ввод и анализ некоторых элементов запросов от конечного пользователя, выраженных на естественном языке или в другой, более "дружественной" форме, чем обыкновенный язык SQL.

4.  Оператор PREPARE извлекает это исходное выражение и подготавливает (т.е. ком пилирует) его, создавая выполняемую версию извлеченного им оператора, сохра няемую в переменной SQLPREPPED.

5.  Оператор EXECUTE выполняет откомпилированную версию оператора из пере менной SQLPREPPED, в результате чего осуществляется собственно операция DELETE. Информация SQLSTATE выполненного оператора DELETE возвращается так же, как при выполнении аналогичного оператора удаления, обычным сбразом.

Обратите внимание, что имя SQLPREPPED идентифицирует переменную языка SQL, a не PL/I, поэтому при его использовании в операторах PREPARE И  EXECUTE  двоеточие перед ним не указывается. Важно также, что подобные переменные SQL явно не объявляются.

Следует отметить, что описанный выше процесс в точности совпадает с процессом,

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

Безусловно, средства динамической поддержки SQL не исчерпываются описанными выше операторами PREPARE И  EXECUTE; например, в них  предусмотрены механизмы параметризации подготавливаемых операторов и  подстановки фактических параметров

вместо формальных параметров перед выполнением динамически сформированных операторов; кроме того, имеются аналоги тех средств курсоров, которые описаны в предыдущем разделе. В частности, в состав этих средств входит оператор  EXECUTE IMMEDIATE, который фактически позволяет объединить функции PREPARE  И EXECUTE В ОДНОЙ операции.

Интерфейсы уровня вызовов SQL/CLI

Средства интерфейса уровня вызовов SQL (SQL Call-Level Interface — SQL/CLI, или сокращенно CLI) были введены в стандарт SQL в 1995 году. Интерфейс CLI в основном создан на базе интерфейса ODBC (Open Database Connectivity) компании Microsoft. И тот, и другой интерфейс позволяет приложениям, которые написаны на одном из базовых языков, выдавать  запросы  к базе данных, обращаясь к процедурам СLI, предоставляемым изготовителем, не прибегая к помощи внедренных операторов SQL. Затем в этих процедурах, которые предварительно должны быть обязательно связаны с данным приложением, используется динамический язык SQL для выполнения требуемых операций с базой данных от имени приложения. (Иными словами, с точки зрения СУБД процедуры CLI ничем не отличаются от обычного приложения.)

Как видим, интерфейс SQL/CLI (а также ODBC) решает ту же задачу, что и динамический язык SQL, а именно — позволяет приложению передавать на выполнение текст оператора SQL именно к тому времени, когда его непосредственно необходимо выполнять. Однако применяемый в интерфейсах CLI и ODBC подход к решению этой задачи организован лучше, чем в динамическом языке SQL. Его преимущества заключаются в следующем.

■  Во-первых, динамический язык SQL — это исходный код, который должен соответствовать стандарту SQL. Поэтому для любого приложения,  которое использует динамический язык SQL, требуется какой-то компилятор SQL, необходимый для обработки установленных стандартом операций, таких как PREPARE, EXECUTE и т.д. Интерфейсом CLI, напротив, нормированы лишь подробности вызова процедур (т.е. в основном вызова подпрограмм). Не требуются средства специального

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

■   Во-вторых, такие приложения могут быть независимыми от типа СУБД,  т.е.  интерфейс SQL/CLI включает средства создания универсальных приложений (опять же, возможно, сторонними изготовителями программного обеспечения), которые могут использоваться для нескольких различных типов СУБД, без специализации с учетом какой-то конкретной СУБД.

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

char sqlsource [65000] ;

strcpy ( sqlsource,

"DELETE FROM SP WHERE QTY < QTY ( 300 )" ) ; rc = SQLExecDirect ( hstmt, (SQLCHAR *)sqlsource, SQL_NTS ) ;

Пояснение

1.         Поскольку в реальных приложениях SQL/CLI базовым языком обычно служит С, в данном примере вместо PL/I используется С. Кроме того, в соответствии со спе цификацией SQL/CLI в именах переменных, именах процедур и т.п. используются прописные буквы (или сочетание прописных и строчных букв), а не только про писные буквы, как во всех остальных именах в этой книге (кроме того, в этих по яснительных примечаниях имена  выделены для  наглядности  моноширинным шрифтом). Необходимо также учитывать, что интерфейс SQL/CLI представляет собой набор стандартных средств для вызова подпрограмм из базового языка, по этому его синтаксис (а также, безусловно, соответствующая семантика) изменяет

ся в зависимости от базового языка.

2.         Функция strcpy языка С вызывается для копирования исходной формы опреде ленного оператора DELETE языка SQL в переменную sqlsource языка С.

3.         Оператор присваивания С ("=") вызывает процедуру SQLExecDirect интерфейса SQL/CLI (аналог оператора EXECUTE IMMEDIATE динамического языка SQL) для выполнения оператора SQL, содержащегося в переменной sqlsource, и при сваивает переменной гс программы С код возврата, полученный в результате этого вызова.

Как и можно было бы предположить, интерфейс SQL/CLI в той или иной  степени включает аналоги всех средств динамического выполнения SQL, наряду с некоторыми дополнениями. Более подробное описание этого интерфейса выходит за рамки данной книги.  Однако  следует  учитывать,  что  такие  интерфейсы,  как CLI,  ODBC  и  JDBC (фактически вариант ODBC для языка Java), приобретают все более важное практическое значение по причинам, которые будут обсуждаться в главе21, раздел 21.6.

Источник: Дейт К. Дж., Введение в системы баз данных, 8-е издание.: Пер. с англ. — М.: Издательский дом «Вильямс», 2005. — 1328 с.: ил. — Парал. тит. англ.

По теме:

  • Комментарии