Д.Д. Чамберлин, М.М.Астрахан, К.П.Эсваран, П.П.Грифитс, Р.А.Лори, Д.В.Мел, П.Райшер, Б.В.Вейд


Средства запросов
Средства манипулирования данными
Средства определения данных
Средства контроля данных
Встраивание в основной язык
Заключение
Приложение. Синтаксис SEQUEL 2
Литература

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

С момента введения Коддом реляционной модели данных как общего средства управления базами данных [1] были предложены несколько реляционных языков данных, предназначенных для неопытных пользователей. Одним из таких языков является SEQUEL, Structured English Query Language [2], который основан на английских ключевых словах и предназначен для использования как неспециалистами в обработке данных, так и профессиональными программстами. К другим хорошо известным языкам аналогичной ориентации относятся QUEL [3], Query By Example [4] и SQUARE [5].

В результате серии тестов, во время которых студенты университета с опытом программирования и без него обучались средствам запросов SEQUEL [6,7], выявились некоторые затруднения в изучении, вызванные возможностями языка. Поэтому в средствах запросов языка было сделано несколько изменений.

Помимо того, SEQUEL был расширен и по другим направлениям: добавлено средство манипулирования данными, которое позволяет вставлять, удалять и модифицировать отдельные кортежи или множества кортежей в реляционной базе данных. Средство определения данных позволяет определять отношения и различные альтернативные представления данных. Средства контроля данных позволяют каждому пользователю предоставлять другим пользователям права доступа к его данным. Средства контроля данных также обеспечивают условия целостности данных и хранимые транзакции, инициируемые различными событиями. Кроме того, к SEQUEL были добавлены средства, которые позволили встраивать его в основные языки программирования высокого уровня, например PL/1.

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

SEQUEL 2 - это основной внешний интерфейс, который будет поддерживаться System R, экспериментальной реляционной системой управления базами данных, которая сейчас находится в процессе разработки [8]. System R сделает SEQUEL 2 доступным как в качестве автономного, ориентированного на дисплей интерфейса, так и в качестве подязыка данных, встроенного в PL/1.

SEQUEL 2 оперирует отношениями в первой (или более высоких) нормальной форме, как описано у Кодда [1,9]. Язык описан здесь с помощью серии примеров, основанных на базе данных из Рис. 1. Отношение EMP описывает множество служащих, присваивая каждому служащему номер, имя, номер отдела, задание, номер руководителя, зарплату и комиссионные. Отношение DEPT задает номер отдела, имя и расположение каждого отдела. Отношение USAGE описывает детали, используемые различными отделами. Отношение SUPPLY описывает компании, которые могут поставлять различные детали. SEQUEL 2 обозначает отношения более привычным термином "таблица" (table). В этой статье термины "отношение" и "таблица" взаимозаменяемы.

В следующих разделах вводятся средства языка SEQUEL 2 для запросов, манипулирования данными, определения данных, контроля данных и встраивания в основной язык. Там, где это необходимо, делается ссылка на определенные возможности System R - однако SEQUEL 2 адаптируется с незначительными модификациями для использования в других реляционных системах. Полный BNF-синтаксис для SEQUEL 2 дан в приложении. SEQUEL 2 допускает запись условий в свободном формате; расположение строк и сдвигов в нижеследующих примерах используется только для ясности.

Средства запросов

Базовая операция языка SEQUEL, называемая отображение (mapping), иллюстрируется в приведенном ниже примере Q1. Отображение предполагает, что известное количество (DNO = 50) должно быть преобразовано в искомое количество (NAME) с помощью отношения (EMP). Фраза SELECT перечисляет атрибуты, которые должны быть возвращены, - если нужен весь кортеж, можно написать SELECT *. Фраза WHERE может содержать любой набор предикатов, которые сравнивают атрибуты кортежа со значениями (например, DNO = 50) или два атрибута кортежа друг с другом (например, SAL < COMM). Предикаты могут соединяться с помощью AND и OR; и могут использоваться скобки, для того чтобы установить старшинство операций.

Q1. Найти имена служащих в отделе 50. 
SELECT NAME 
FROM EMP 
WHERE DNO = 50 

В общем случае, отображение возвращает набор значений - выбранные атрибуты кортежа, которые удовлетворяют фразе WHERE. Дублированные значения не исключаются из возвращенного множества, если пользователь не потребует этого, написав SELECT UNIQUE. Мы определили это условие, поскольку исключение дублированных значений - это дорогая операция, которая, по нашему мнению, не должна выполняться по умолчанию. В Q2 иллюстрируется "проекция" отношения EMP на атрибут DNO.

Q2. Перечислить все различные номера отделов в таблице EMP. 
SELECT UNIQUE DNO 
FROM EMP 

Предикат во фразе WHERE может проверять атрибут на принадлежность множеству, как показано в Q3, где также иллюстрируется представление множества констант.

Q3. Перечислить имена служащих в отделах 25, 47 и 53. 
SELECT NAME 
FROM EMP 
WHERE DNO IN (25,47,53) 

Возможно использование результата отображения во фразе WHERE в другом отображении. Эта операция, называемая вложенным отображением (nested mapping), иллюстрируется в Q4. Внутреннее отображение возвращает набор DNO значений отделов, расположенных в EVANSTON. Затем внешнее отображение выполняется так, как если бы ему было дано множество констант на месте внутреннего отображения. Может быть любое количество уровней вложения отображений. Оператор сравнения = может использоваться вместо IN без изменения смысла запроса (пользователю это может показаться более естественным, когда внутреннее отображение возвращает одно значение).

EMP

EMPNO

NAME

DNO

JOB

MGR

SAL

COMM

DFPT

DNO

DNAME

LOC





USAGT

DNO

PART






SUPPLY

SUPPLIER

PART






Рисунок 1.
Пример базы данных.

Q4. Найти имена служащих, которые работают в отделах, расположенных в EVANSTON. 
SELECT NAME 
FROM EMP 
WHERE DNO IN 
SELECT DNO 
FROM DEPT 
WHERE LOC = "EVANSTON" 

В SEQUEL 2 требуется заключать символьно-строковые константы в одинарные кавычки, для того чтобы отличить их от имен атрибутов (например, NAME = JOB и NAME = "JOB" являются правильными предикатами, но с различными значениями). Кавычки являются необязательными для числовых констант (например, SAL = 10000 и SAL = "10000" эквивалентны).

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

Q5. Перечислить номер служащего, его имя и зарплату 
для служащих отдела 50, в порядке номеров служащих. SELECT EMPNO,NAME,SAL FROM EMP WHERE DNO = 50 ORDER BY EMPNO

SEQUEL 2 обеспечивает несколько встроенных функций, которые могут использоваться во фразе SELECT, как показано в Q6. Эти функции включают AVG, SUM, COUNT, MAX и MIN. System R позволяет добавлять дополнительные функции к системе, размещая программы в специальной библиотеке функций.

Q6. Найти среднюю зарплату клерков. 
SELECT AVG(SAL) 
FROM EMP 
WHERE JOB = "CLERK" 

Нотация COUNT(*) обозначает количество кортежей, которые удовлетворяют фразе WHERE.

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

Q7. Сколько различных заданий у служащих в отделе 50? 
SELECT COUNT(UNIQUE JOB) 
FROM EMP 
WHERE DNO = 50 

Кроме простых атрибутов и встроенных функций пользователь может конструировать арифметические выражения во фразе SELECT. Все перечисленные ниже выражения являются правильными:

AVG(SAL)/52 
AVG(SAL)+AVG(COMM) 
AVG(SAL+COMM) 

Отношение может быть разделено на группы в соответствии с значением некоторого атрибута, затем встроенная функция применяется к каждой группе. Этот тип запроса показан в Q8. Фраза GROUP BY всегда используется вместе со встроенной функцией. Когда используется фраза GROUP BY, каждый элемент во фразе SELECT должен быть уникальным свойством группы, а не индивидуального кортежа. Например, в Q8 каждая группа служащих имеет уникальный DNO и уникальную среднюю зарплату. Если во фразе SELECT в Q8 добавить EMPNO, возникнет ошибка, так как EMPNO не является уникальным свойством каждой группы.

Q8. Перечислить все отделы и среднюю зарплату в каждом. 
SELECT DNO,AVG(SAL) 
FROM EMP 
GROUP BY DNO 

Отношение может быть разделено на группы, затем применяется предикат или набор предикатов для выбора только некоторых групп и отбрасывания других. Эти предикаты квалификации групп всегда основаны на встроенных функциях и размещаются в специальной фразе HAVING, как показано в Q9. Предикат во фразе HAVING может сравнивать составное свойство группы с константой (например, AVG(SAL) < 10000) или с другим составным свойством той же самой группы (например, AVG(SAL) <= AVG(COMM)).

Q9. Перечислить те отделы, в которых средняя зарплата служащих не превышает 10000. 
SELECT DNO 
FROM EMP 
GROUP BY DNO 
HAVING AVG(SAL)<10000 

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

Q10. Перечислить отделы, в которых работает более десяти клерков. 
SELECT DNO 
FROM EMP 
WHERE JOB = "CLERK" 
GROUP BY DNO 
HAVING COUNT(*) > 10 

Предоставляется специальная встроенная функция SET, которая преобразует во множество значений определенный атрибут, присутствующий в данной группе. После чего это множество атрибутов можно сравнивать с другим множеством во фразе HAVING. В Q11 внутреннее отображение возвращает множество всех заданий в таблице EMP (с дубликатами). Внешнее отображение группирует служащих по номерам отделов и затем выбирает те группы, множество заданий которых эквивалентно множеству всех заданий. В этом случае оператор "=" используется для сравнения двух множеств. К другим операторам сравнения множеств относятся ¬ =, [IS] [NOT] IN, CONTAINS и DOES NOT CONTAIN. Все эти операторы сравнения множеств исключают дубликаты из обоих своих опреандов до того, как будет выполнено сравнение.

Q11. Перечислить отделы, в которых есть служащие с каждым возможным заданием. 
SELECT DNO 
FROM EMP 
GROUP BY DNO 
HAVING SET(JOB) = 
SELECT JOB 
FROM EMP 

Теоретико-множественные операторы INTERSECT, UNION и MINUS также доступны в SEQUEL 2. Они могут использоваться для комбинирования результатов двух отображений, как показано в Q12. Запрос может содержать несколько теоретико-множественных операторов, скобки используются при необходимости для разрешения неоднозначностей. Как и перечисленные выше операторы сравнения множеств, INTERSECT, UNION и MINUS автоматически исключают дубликаты из операндов до своего выполнения.

Q12. Перечислить отделы, в которых нет служащих. 
SELECT DNO 
FROM DEPT 
MINUS 
SELECT DNO 
FROM EMP 

Запрос может возвращать значения, выбранные из более чем одного отношения. Пример - операция соединения (join), которую иллюстрирует Q13. Пользователь может перечислить несколько отношений во фразе FROM. Концептуально, формируется декартово произведение этих отношений, затем оно фильтруется предикатами во фразе WHERE. (Конечно, хорошо спроектированная система будет избегать фактического образования декартова произведения, но достигнет того же результата с помощью более эффективных средств.) Когда во фразе FROM указывается более одного отношения, пользователь должен быть внимателен, тщательно квалифицируя каждое имя атрибута во фразах SELECT и WHERE (например, для того чтобы отделить EMP.DNO от DEPT.DNO). Если имя атрибута появляется только в одном из участвующих отношений, его не нужно квалифицировать (например, в Q13 можно было бы указать просто SELECT NAME,LOC).

Q13. Перечислить имена всех служащих и расположение их отделов. 
SELECT EMP.NAME,DEPT.LOC 
FROM EMP,DEPT 
WHERE EMP.DNO = DEPT.DNO 

В некоторых типах запросов необходимо связывать отношение с самим собой в соответствии с определенными критериями. Это можно сделать, указав имя отношения больше чем один раз во фразе FROM, как показано в Q14. В таком запросе пользователь может придумать произвольную метку для связи с каждым из участвующих отношений (в этом примере в качестве меток выбраны X и Y). Эти метки могут затем использоваться вместо имени отношения для квалификации ссылок во фразах SELECT и FROM.

Q14. Для каждого служащего, зарплата которого выше зарплаты его руководителя, 
перечислить имя служащего и имя его руководителя. 
SELECT X.NAME, Y.NAME 
FROM EMP X, EMP Y 
WHERE X.MGR = Y.EMPNO 
AND X.SAL > Y.SAL 

Язык SEQUEL 2 также позволяет использовать метку для квалификации имен атрибутов вне блока отображения, в котором определена метка. Например, в Q15 ищутся кортежи X отношения SUPLLY, такие, что множество деталей, поставляемых компанией в кортеже X (вычисленное в первом вложенном отображении), содержит множество деталей, используемых отделом 50 (вычисленное во втором вложенном отображении).

Q15. Перечислить компании, которые поставляют все детали, используемые отделом 50. 
SELECT SUPPLIER 
FROM SUPPLY X 
WHERE 
(SELECT PART 
FROM SUPPLY 
WHERE SUPPLIER = X.SUPPLIER) 
CONTAINS 
(SELECT PART 
FROM USAGE 
WHERE DNO = 50) 

Мы разрабатывали SEQUEL 2 таким образом, чтобы всякий раз, когда переменная появляется вне блока, в котором она определена, ее можно было внести в этот блок (и часто совсем исключить) с помощью GROUP BY и специальной функции SET. Например, Q16 эквивалентен Q15.

Q16. (Эквивалентно Q15.) 
SELECT SUPPLIER 
FROM SUPPLY 
GROUP BY SUPPLIER 
HAVING SET(PART) CONTAINS 
SELECT PART 
FROM USAGE 
WHERE DNO = 50 

Нотация для множества констант показана в Q3. Кортеж констант обозначается, как показано в следующем примере:

<"CLERK",50> 

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

(<"CLERK",50>, <"CLERK",52>, <"PROGRAMMER",52>) 

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

Q17. Перечислить имена служащих, которые имеют те же задание и зарплату, что и Смит. 
SELECT NAME 
FROM EMP 
WHERE  = 
SELECT JOB,SAL 
FROM EMP 
WHERE NAME = "SMITH" 

В SEQUEL 2 возможно существование неизвестных, или null-значений в базе данных. На null-значение ссылаются с помощью ключевого слова NULL. Null-значения игнорируются при вычислении всех встроенных функций, за исключением COUNT (например, неизвестные зарплаты не участвуют в вычислении AVG(SAL)).

AND T F ?
T
F
?
T F ?
F F F
? F ?
OR T F ?
T
F
?
T T T
T F ?
T ? ?
NOT
T
F
?
F
T
?
IF X THEN Y Y=T Y=F Y=?
X=T
X=F
X=?
T F ?
T T T
T ? ?

Рисунок 2.
Таблицы истинности для трехзначной логики.

При определении, удовлетворяет ли данный кортеж фразе WHERE запроса, предикатам, тестирующим атрибуты, для которых кортеж содержит null-значение, присваивается неизвестное значение истинности. Затем вычисляется значение истинности всей фразы WHERE с использованием трехзначной логики для вычисления AND"ов и OR"ов (см. Рис. 2). Кортеж считается удовлетворяющим фразе WHERE, если итоговое значение истинности фразы - TRUE, но не в случае FALSE. Например, кортеж, имеющий DNO, равный 50, и неопределенную зарплату, будет удовлетворять Q18, но не Q19.

Q18. 
SELECT * 
FROM EMP 
WHERE DNO = 50 
OR SAL > 15000 Q19. 
SELECT * 
FROM EMP 
WHERE DNO = 50 
AND SAL > 15000 

Исключение из перечисленных выше правил делается в случае предикатов, которые явно ищут null-значения, например: WHERE SAL = NULL. В этих предикатах null-значение обрабатывается так же, как и любое другое значение.

Средства манипулирования данными

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

Средство вставки позволяет пользователю вставлять новый кортеж или множество кортежей в отношение. Вставка одного кортежа иллюстрируется примером М1. Атрибутам, которые не определены оператором вставки, присваиваются null-значения. Если у кортежа, который должен быть вставлен, все атрибуты приведены в правильном порядке, список имен атрибутов может быть опущен.

М1. Вставить нового служащего по имени "Jones"
с номером 535 из отдела 51 с неопределенными остальными атрибутами. INSERT INTO EMP(EMPNO,NAME,DNO): <535,"JONES",51>

Оператор вставки языка SEQUEL может также вычислять запрос и вставлять результирующее множество кортежей в некоторое существующее отношение. Предположим, база данных содержит отношение CANDIDATES, которое имеет столбцы для номера служащего, имени, номера отдела и зарплаты. Затем можно использовать М2 для выбора множества значений из отношения EMP и вставки их в CANDIDATES.

М2. Добавить в таблицу CANDIDATES всех тех служащих, 
комиссионные которых больше половины их зарплаты. 
INSERT INTO CANDIDATES: 
SELECT EMPNO,NAME,DNO,SAL 
FROM EMP 
WHERE COMM > 0.5 * SAL 

Удаление - это процесс спецификации кортежей, которые должны быть удалены из базы данных. Кортежи определяются с помощью фразы WHERE, которая синтаксически идентична фразе WHERE запроса, как показано в М3.

М3. Удалить из EMP служащего с номером 561. 
DELETE EMP 
WHERE EMPNO = 561 

Иногда может быть полезно придумать метку для кортежей, которые должны быть удалены, и затем использовать эту метку для определения свойств кортежей. Это аналогично использованию меток в средствах запросов языка. Удаление с использованием метки показано в М4.

М4. Удалить все отделы, в которых нет служащих, из таблицы DEPT. 
DELETE DEPT X 
WHERE(SELECT COUNT (*) FROM EMP 
WHERE DNO = X.DNO) = 0 

Средства модификации SEQUEL 2 аналогичны средствам удаления, за исключением использования фразы SET для указания модификаций, которые должны быть сделаны в выбранных кортежах. Новые значения для модифицированных атрибутов могут быть выражены как константы, как вложенные запросы или как выражения, основанные на первоначальных значениях атрибутов, как показано в М5. Как и в случае удаления, во фразу UPDATE можно поместить метку и использовать ее во вложенных запросах во фразах SET или WHERE.

М5. Модифицировать таблицу EMP, повысив на 10 процентов зарплату всем тем служащим, 
номер которых содержится в таблице CANDIDATES. 
UPDATE EMP 
SET SAL = SAL * 1.1 
WHERE EMPNO IN 
SELECT EMPNO 
FROM CANDIDATES 

Вновь вставленные или модифицированные кортежи не проверяются на дублирование существующего кортежа, так как в SEQUEL разрешается существование дублированных кортежей, если пользователь не указал иначе. В версии System R языка SEQUEL дублированные кортежи могут быть запрещены с помощью "уникального образа" (объясняется в следующем разделе).

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

М6. Создать новое отношение MANAGERS (с подходящими именами столбцов) и 
разместить в нем номер служащего, имя, номер отдела и зарплату всех служащих, 
которые являются руководителями. 
ASSIGN TO MANAGERS (EMPNO,NAME,DEPT,SALARY): 
SELECT EMPNO,NAME,DNO,SAL 
FROM EMP 
WHERE EMPNO IN 
SELECT MGR 
FROM EMP 

Новое отношение, созданное оператором присваивания, не зависит от отношения (-ий), из которых оно выведено. Когда М6 выполнено, добавление нового руководителя в таблицу EMP не влияет на отношение MANAGERS, а модификация MANAGERS не влияет на EMP.

Средства определения данных

Средства определения данных позволяют создавать и удалять отношения, определять альтернативные представления отношений и специфицировать способы доступа (индексы и т.д.), которые будут поддерживаться в базе данных. Средства определения данных языка описывают структуры данных, предоставляемые системой, в которой функционирует язык. В этом разделе описаны операторы определения данных SEQUEL 2 в контексте System R. Могут быть сделаны соответсвующие модификации, для того чтобы адаптировать этот язык к другим реляционным системам.

Пример D1 - это оператор, создающий новое отношение (таблицу), которое должно физически храниться в системе. System R разрешает создавать и удалять таблицы динамически. Пользователь специфицирует имя таблицы, имена столбцов и типы данных. Если null-значения не могут быть разрешены в определенном столбце (например, столбец DNO в примере), пользователь может это указать. Типы данных, поддерживаемые System R, показаны в Приложении.

D1. (Это оператор, который мог бы быть использован для создания таблицы DEPT
.
) 
CREATE TABLE DEPT 
(DNO(CHAR(2),NONULL), 
DNAME(CHAR(12) VAR), 
LOC(CHAR(20) VAR) ) 

В SEQUEL 2 имя таблицы может квалифицироваться, если необходимо, именем пользователя, который ее создал. Например, если пользователи Смит и Джонс каждый создали таблицу с именем EMP, Смит может ссылаться на свою собственную таблицу по имени EMP или на таблицу Джонса (если у него есть такие права) по имени JONES.EMP. Пользователь может также определить синоним, или альтернативное имя, для таблицы, как показано в D2. Этот метод допускает ссылки на таблицу, созданные другим пользователем, без повторения имени автора в каждой ссылке.

D2. Определить JEMP как синоним для таблицы EMP, созданной Джонсом. 
DEFINE SYNONYM JEMP AS JONES.EMP 

Способы доступа, поддерживаемые System R, называются образами и линками [8]. Образ (image) - это индекс для одного или более атрибутов, поддерживаемый в форме В-дерева [10]. Не более одного образа в отношении может иметь кластерное (clustering) свойство, которое означает, что кортежи, которые в упорядочении образа находятся рядом друг с другом, физически расположены рядом друг с другом в базе данных. Образ может быть также определен как уникальный (unique), что означает, что индексированный атрибут должен быть ключом этого отношения, то есть, никакие два кортежа не могут иметь одно и то же значение для этого атрибута. Линк (link) - это множество указателей для соединения кортежей одного отношения с кортежами другого отношения, которые выбраны в соответствии с определенным атрибутом. Линк может иметь кластерное свойство, в этом случае система пытается поддерживать физическую смежность кортежей на линке. Примеры операторов, которые создают кортежи и линки, показаны в D3 и D4. Каждому образу или линку дано имя (I3 и L5 в примерах), которые дают возможность пользователю ссылаться на них (например, в операторе DROP).

D3. Создать образ I3 для атрибута SAL в таблице EMP. 
CREATE IMAGE I3 ON EMP(SAL) 
D4. Создать линк L5, который соединяет строки DEPT с теми строками EMP, 
которые соответствуют атрибуту DNO. Упорядочить служащих на линке по JOB и затем по SAL. 
CREATE LINK L5 
FROM DEPT(DNO) 
TO EMP(DNO) 
ORDER BY JOB,SAL 

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

Очень важный аспект определения данных - возможность определять альтернативные представления хранимых данных. В SEQUEL 2 процесс определения представления очень похож на процесс задания запроса. Это происходит потому, что SEQUEL 2 имеет свойство замкнутости (closure): результат любого запроса к одной или более таблиц сам является таблицей. Следовательно, формулировка любого запроса может использоваться как определение представления. Оператор DEFINE VIEW дает имя представлению и его столбцам. (Если имена столбцов могут быть одназначно выведены из запроса, определяющего представление, они могут быть опущены.) После определения представления оно может использоваться точно также, как используется хранимая таблица: к нему можно обращаться с запросами, другие представления могут определяться в его терминах и, при некоторых ограничениях [11], оно может модифицироваться. В отличие от описанного выше оператора присваивания, представление - это динамическое окно в базу данных. Изменения, сделанные в лежащих в его основе отношениях, видимы через представление. В общем случае, модификации могут делаться через представления, только если каждый кортеж представления связан в точности с одним кортежем хранимого отношения. Это позволяет обновлять кортежи представления с помощью модификаций соответствующих хранимых кортежей.

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

D5. Определить представление D50, содержащее номер, имя и задание служащих в отделе 50. 
DEFINE VIEW D50 AS 
SELECT EMPNO,NAME,JOB 
FROM EMP 
WHERE DNO = 50 

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

Представление не обязательно выводится из одного отношения. Например, D6 определяет представление как соединение двух таблиц с помощью запроса, аналогичного Q13. Пример D6 также показывает, как можно сделать запрос к представлению, так как если бы оно было хранимым отношением. Определяя соединенное представление, такое, например, как в D6, пользователи должны остерегаться "ловушки соединения", описанной Коддом [1]. В терминах D6, из фактов, что служащий X работает в отделе Y и отдел Y находится в месте Z, не обязательно следует, что служащий X находится в Z.

D6. Определить представление PROGS,
состоящее из имен и зарплат всех программистов
и мест расположения их отделов. DEFINE VIEW PROGS (NAME,SALARY,HOMEBASE) AS SELECT EMP.NAME,EMP.SAL,DEPT.LOC FROM EMP,DEPT WHERE EMP.DNO = DEPT.DNO AND EMP.JOB = "PROGRAMMER"

Используя приведенное выше представление, найти среднюю зарплату программистов в Денвере.

SELECT AVG(SAL) 
FROM PROGS 
WHERE HOMEBASE = "DENVER" 

Иногда может быть необходимо расширить существующую таблицу, добавив в нее новый столбец, например для того, чтобы можно было работать с новым приложением. SEQUEL 2 позволяет добавлять столбцы в правую часть существующих таблиц с помощью оператора EXPAND, который указывает имя и тип данных нового столбца. Считается, что существующие кортежи имеют в новом столбце null-значения до тех пор, пока они не будут модифицированы. На запросы и представления, которые были написаны в терминах существующей таблицы, расширение не влияет (за исключением тех запросов, которые включают оператор выбора из таблицы SELECT * ).

D7. Добавить новый столбец NEMPS, целого типа,
в таблицу DEPT. 
EXPAND TABLE DEPT 
ADD COLUMN NEMPS(INTEGER) 

Когда в таблицах, представлениях, образах и линках необходимости больше нет, они могут быть удалены из системы командой DROP, как показано в D8.

D8. Удалить представление D50. 
DROP VIEW D50 

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

System R автоматически поддерживает каталоги, описывающие все таблицы, представления, образы, линки, условия и триггеры (см. следующий раздел), которые известны системе. Эти каталоги хранятся в форме таблиц, к которым можно обращаться с запросами точно также, как к любой другой таблице. В каждом элементе каталога есть место для комментария, которое может быть заполнено автором соответствующего объекта с помощью оператора COMMENT:

D9. (Иллюстрирует использование комментариев.) 
COMMENT ON VIEW D50: 
"LIMITED VIEW OF EMPLOYEES
IN DEPT.50" 

Средства контроля данных

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

Так как SEQUEL позволяет любому пользователю создавать новые отношения и представления, на каждого пользователя ложится ответственность за контроль доступа к объектам данных, которые он создает. Когда пользователь создает отношение или представление, он получает все права по выполнению действий над ним. (Если объект - это представление, права пользователя ограничиваются теми правами, которые он имеет для базового отношения.) Пользователь может предоставить доступ к своему отношению или представлению другим пользователям с помощью команды GRANT языка SEQUEL. Могут быть предоставлены следующие привилегии:

  • READ
  • INSERT
  • DELETE
  • UPDATE (по столбцам)
  • EXPAND
  • IMAGE (для определения образов на отношении)
  • LINK (для создания линков на отношении)
  • CONTROL (для задания условий или определения триггеров, относящихся к отношению - объяснение приведено ниже).

Дополнительная привилегия RUN, которая применяется к программам, а не к отношениям, объясняется в следующем разделе.

Кроме того, пользователь, передающий права, может позволить тому, кому права предназначаются, передавать перечисленные привилегии другим пользователям, включив фразу WITH GRANT OPTION. Если пользователь не имеет возможности передавать привилегию, он может воспользоваться этой привилегией, но не может передавать ее другим пользователям.

С1. Дать следующие привилегии на таблицу EMP Смиту и Андерсону: 
возможность читать, вставлять, модифицировать столбцы JOB и DNO и 
передавать эти возможности другим. 
GRANT READ, INSERT, UPDATE(JOB,DNO) ON EMP 
TO SMITH, ANDERSON WITH GRANT OPTION 

Ключевое слово PUBLIC может использоваться вместо списка пользователей, которым должна быть передана привилегия, если она должна быть передана всем пользователям. Фраза ALL RIGHTS может использоваться вместо списка привилегий в операторе GRANT. Если список привилегий опущен, по умолчанию передается привилегия READ.

После того как привилегия передана, ее можно лишить с помощью команды REVOKE. Названные привилегии отбираются у того, кому они переданы, и у всех пользователей, которым они их, в свою очередь, передали, если не имеется другого, независимого источника отбираемых привилегий. Лишение привилегии может также иметь другие последствия. Например, если у пользователя отбирается привилегия READ на отношение EMP, все представления, определенные на EMP этим пользователем, должны быть уничтожены. Эти проблемы более подробно рассматриваются в работе [12].

С2. Лишить Андерсона возможности модифицировать таблицу EMP. 
REVOKE UPDATE ON EMP FROM ANDERSON 

Язык SEQUEL дает возможность пользователю, который имеет привилегию CONTROL на таблицу, определять условия (assertions) целостности данных в этой таблице. Условие - это предикат, который может иметь значения TRUE или FALSE. Когда встречается оператор ASSERT, система проверяет текущее значение истинности предиката. Если в данный момент оно равно FALSE, условие отбрасывается. Если - TRUE, система с этого момента обязывает применять это условие ко всем дальнейшим модификациям в базе данных. Каждому условию дается имя тем пользователем, который его определяет. Если оператор вставки, удаления или модификации нарушает условие, этот оператор отбрасывается и возвращается код нарушения, вместе с именем (-ами) нарушенного условия (-й).

Простейший тип условий относится к заданному отношению (идентифицированному фразой типа ON EMP) и должен применяться к каждому кортежу отношения.

С3. Задать условие, что зарплата всех служащих меньше 50000. 
ASSERT A1 ON EMP: SAL < 50000 
С4. Задать условие, что все клерки получают зарплату между 8000 и 15000. 
ASSERT A2 ON EMP: 
IF JOB = "CLERK" THEN 
SAL BETWEEN 8000 AND 15000 

Как и в запросах, с условием можно связывать метку. Эта метка может затем использоваться в блоках отображения в пределах условия для определения некоторого свойства, которое должно иметь силу для всех кортежей отношения, на котором применяется условие. Использование метки в условии показано в С5.

С5. Задать условие, что атрибут NEMPS каждой строки таблицы DEPT равен 
числу служащих в данном отделе. 
ASSERT A3 ON DEPT X: NEMPS=
(SELECT COUNT(*) 
FROM EMP
WHERE DNO = X.DNO) 

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

С6. Задать условие, что ни одна строка в таблице ЕМР не может иметь DNO, 
не присутствующий в таблице DEPT. 
ASSERT A4:
(SELECT DNO FROM EMP) 
IS IN
(SELECT DNO FROM DEPT) 

Представленные до сих пор условия иллюстрируют состояния, которые должны поддерживаться статически. Другой класс условий имеет дело с переходами (transition) в базе данных. Условие этого типа должно задавать обстоятельства, при которых оно должно выполняться: при вставке, удалении или модификации кортежей в некотором отношении. Когда указанное действие выполняется над кортежем данного отношения, проверяется тело условия для определения, допустим ли такой переход. Переход может быть описан c помощью значений OLD или NEW, которые представляют атрибуты кортежа до и после перехода. Если один оператор SEQUEL модифицирует много кортежей, условие проверяется для каждого кортежа, и отбрасывается весь оператор, если какой-либо кортеж нарушает условие.

С7. Задать условие, что при каждом изменении зарплаты служащего, 
новая зарплата должна быть по крайней мере не меньше старой. 
ASSERT A5 ON UPDATE OF EMP(SAL): 
NEW SAL >= OLD SAL 

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

Общее правило для обработки null-значений при проверке условия состоит в том, что наличие null-значений никогда не должно вызывать выполнение условия, если в противном случае оно не выполняется, или его невыполнение, если в противном случае оно выполняется. Это правило реализуется с помощью трехзначной логики. Предикат условия, который в общем случае может быть булевским выражением, вычисляется с помощью таблицы истинности (Рис. 2). Условие выполняется, если результат равен TRUE или ?, и нарушается, если результат равен FALSE. Например, условие, что ни одна зарплата не превышает 20000, не нарушается в случае неизвестного жалованья. Исключение из этого правила делается в том случае, когда условия явно ссылаются на null-значения, например, EMPNO ¬ = NULL. В таких условиях null-значение обрабатывается так же, как любое другое значение.

SEQUEL позволяет группировать несколько операторов в транзакцию, размещая их между операторами BEGIN TRANSACTION и END TRANSACTION. Условия целостности обычно приостанавливаются в пределах транзакции. В конце транзакции проверяются все относящиеся к ней условия и, если какое-либо нарушается, отбрасывается вся транзакция. Это позволяет производить модификации, которые вызывают переход базы данных через временно противоречивые состояния. Например, если нанимается новый служащий, могут быть сделаны изменения в EMP и DEPT, которые приведут к тому, что база данных на мгновение нарушит условие А3 из примера С5. Однако в конце транзакции условие А3 будет выполнено.

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

В System R размещение нескольких операторов в транзакции имеет дополнительное значение, определяя, что система должна выполнять эти операторы как отдельное действие, не допуская вмешательства (например, модификации соответствующих данных) со стороны других пользователей во время транзакции. Настолько, насколько возможно, System R пытается защитить каждого пользователя от любого проникновения других, работающих одновременно, пользователей. Следовательно, SEQUEL не требует от пользователя операторов блокировки или специальных операторов модификации. Установка и сброс блокировок, обнаружение и разрешение тупиковых ситуаций оставлены системе исполнения. Эти проблемы и их реализация в System R более подробно обсуждаются в работе [8].

В любой момент в пределах транзакции пользователь может описать "точку сохранения" с помощью оператора SAVE <имя-точки сохранения>. В одной транзакции может быть описано много точек сохранения. В любой момент пользователь может отменить все изменения, сделанные им в базе данных с момента определенной точки сохранения, с помощью оператора RESTORE <имя-точки сохранения>. Если в операторе RESTORE имя точки сохранения опущено, отмена производится с начала текущей транзакции. Ни один оператор RESTORE не может делать отмену с точки сохранения, находящейся до начала текущей транзакции. Оператор RESTORE не влияет на изменения, которые сделаны другими пользователями.

Для того чтобы помочь поддерживать целостность базы данных, пользователь может определить триггер (trigger), который будет выполняться при появлении определенного действия: READ, INSERTION, DELETE или UPDATE - над кортежем в некоторой заданной таблице. Тело триггера, которое состоит из одного или более операторов SEQUEL, выполняется сразу же после выполнения указанного действия любым пользователем. Если оператор SEQUEL выполняет действие, например модификацию, над многими кортежами, и это действие вызывает триггер, триггер выполняется повторно, сразу после модификации каждого кортежа. Триггеры всегда выполняются немедленно и не могут быть отложены до конца транзакции. Тело триггера может использовать слова OLD и NEW для ссылки на предыдущее и модифицированное значения кортежа, как показано в С8.

С8. (Этот триггер автоматически модифицирует соответствующие элементы NEMP 
в таблице DEPT при каждой модификации DNO служащего.) 
DEFINE TRIGGER T1 
ON UPDATE OF EMP(DNO): 
(UPDATE DEPT 
SET NEMPS = NEMPS + 1 
WHERE DNO = NEW EMP.DNO 
UPDATE DEPT 
SET NEMPS = NEMPS - 1 
WHERE DNO = OLD EMP.DNO 

К кортежу, который вызывает триггер, может быть присоединена метка, и эта метка может использоваться в теле триггера. Кроме того, оператор в теле триггера может содержать фразу IF, которое делает его выполнение зависимым от некоторых условий, как показано в С9.

С9. Когда служащий удаляется из EMP, удалить соответствующую запись в DEPT, 
если в этом отделе больше не остается служащих. 
DEFINE TRIGGER T2 
ON DELETION OF EMP X: 
(IF (SELECT COUNT(*) 
FROM EMP 
WHERE DNO = X.DNO) = 0 
THEN DELETE DEPT 
WHERE DNO = X.DNO) 

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

Условия перехода (например условия, которые сравнивают значения OLD и NEW кортежа) всегда применяются, как и триггеры, по принципу кортеж-за-кортежем. Условие перехода сравнивает значение кортежа до его модификации со значением после модификации и выполнения всех триггеров, вызванных при модификации этого кортежа.

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

DROP TRIGGER T2 

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

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

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

Встраивание в основной язык

SEQUEL 2 спроектирован таким образом, что может использоваться как в качестве автономного языка для интерактивных пользователей, так и в качестве подъязыка данных, встроенного в основной язык программирования. Возможности, рассмотренные в предыдущих разделах, описывались с точки зрения интерактивного пользователя. В этом разделе описываются дополнительные возможности языка, которые обеспечиваются для связи с основным языком. Там, где это необходимо, мы ссылаемся на специфические детали реализации System R.

System R обеспечивает использование операторов SEQUEL в качестве операторов программы PL/1. Операторы SEQUEL распознаются прекомпилятором, который заменяет их правильными вызовами PL/1 к модулю времени выполнения, который и выполняет нужную функцию.

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

Р1. Возвратить задание служащего с номером 507 в программную переменную X и 
его зарплату в программную переменную Y. 
SELECT JOB,SAL 
INTO X,Y 
FROM EMP 
WHERE EMPNO = 507; 

Кроме фразы INTO, программные переменные могут появляться везде, где может использоваться константа, в запросе или операторе SEQUEL любого другого типа. Всюду, где появляется программная переменная, программист может дополнительно определить пару имен переменных, разделенных двоеточием. Первая переменная этой пары называется хранителем значения, а вторая, которая должна иметь тип данных BIN FIXED, называется null-индикатором. Ноль в null-индикаторе означает фактическое значение в хранителе значения; отрицательное значение в null-индикаторе означает null-значение. Эти возможности иллюстрируются в Р2.

Р2. Возвратить в программную переменную Х1 зарплату служащего, 
чей номер находится в программной переменной Z1. (Переменные Х2 и Z2 
служат в качестве null-индикаторов.) 
SELECT SAL 
INTO X1:X2 
FROM EMP 
WHERE EMPNO = Z1:Z2; 

Всякий раз, когда имя описанной программной переменной дублирует имя столбца в базе данных (например, WHERE SAL = COMM, если COMM - описанная программная переменная), система предполагает, что это ссылка на программную переменную, а не на столбец.

В приведенных выше примерах в основную программу возвращается только один кортеж (если запрос вычисляет более одного кортежа, возвращается только первый). Чаще, однако, программисту может понадобиться идентифицировать множество кортежей и обрабатывать их один за другим. Для этой цели мы ввели понятие курсора. Курсор - это символическое имя, которое программист может связать с запросом и использовать для выборки результата запроса, по одному кортежу в каждый момент времени, как показано в Р3.

Р3. Прочитать номер отдела с терминала, затем найти и вывести 
имена служащих данного подразделения. (Операторы, помеченные 
с левого края звездочкой, обрабатываются прекомпилятором SEQUEL. 
Все остальные - стандартные операторы PL/1. Звездочки не являются частью программы.) 
P3: PROC OPTIONS(MAIN); 
DCL X CHAR(50), Y CHAR(2); 
* LET C1 BE 
* SELECT NAME INTO X 
* FROM EMP WHERE DNO = Y; 
DISPLAY("DNO?") REPLY(Y); 
* OPEN C1; 
DO WHILE (CODE = OK); 
* FETCH C1; 
DISPLAY(X); 
END; 
* CLOSE C1; 
END P3; 

В этом примере описания X и Y - стандартны для PL/1. Оператор LET C1 BE <запрос> подобен объявлению для системы базы данных и связывает имя курсора С1 с данным запросом. Оператор OPEN С1 использует значение входной переменной Y и подготавливает обработку кортежей в соответствии с запросом. Каждое выполнение FETCH C1 помещает новый кортеж в программную переменную(-ые), определенную запросом. CODE - это специальная переменная, в которую система управления базой данных помещает код результата каждого обращения к базе данных. (Здесь мы не приводим полную обработку кодов результата.) Оператор CLOSE C1 сообщает системе, что больше не будет делаться выборки по запросу, в данный момент связанному с С1. Если С1 открывается повторно, входная переменная Y повторно связывается с другим, возможно, значением, и может быть выбрано новое множество кортежей.

При каждом открытии курсора он содержит позицию во множестве кортежей, на котором он определен (так называемое активное множество). Если каждый кортеж активного множества однозначно связан с кортежем отношения (например, запрос включает ключ отношения), говорят, что курсор является обновляемым. Это означает, что на текущую позицию курсора можно ссылаться в операторах UPDATE или DELETE для обозначения кортежа, который будет модифицироваться или удаляться. Предположим, например, что нам нужно модифицировать программу в Р3, так чтобы она повышала зарплату каждому служащему в указанном отделе. Это можно сделать, заменив цикл DO в Р3 следующим:

DO WHILE (CODE = OK); 
* FETCH C1; 
/* Вычислить новую зарплату для этого 
служащего в программной переменной Z */ 
* UPDATE EMP 
* SET SAL = Z 
* WHERE CURRENT OF C1; 
END; 

Если фраза WHERE CURRENT OF <имя-курсора> используется в операторе модификации или удаления, ее нельзя смешивать с другими предикатами выбора. Ссылка на курсор не может использоваться в операторе INSERT, так как отношения являются неупорядоченными объектами, и, следовательно, вставка с помощью курсора не определена.

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

Р4. Предположим, С2 спозиционирован на кортеж в DEPT. 
Определить С5 как множество кортежей EMP, 
DNO которых соответствует кортежу в DEPT, 
на который указывает С2. 
LET C5 BE 
SELECT * FROM EMP 
WHERE DNO = DNO OF CURSOR C2
ON DEPT; 

Заметим, что CURRENT OF C2 обозначает фактический кортеж, на который указывает С2, но DNO = DNO OF CURSOR C2 ищет другое множество кортежей по соответствию значений. Фраза ON DEPT сообщает System R, что курсор С2 указывает на кортеж в DEPT. Этот факт может быть полезен при выборе пути доступа (например, может быть линк из DEPT к EMP по соответствию DNO). Ни один из двух типов ссылок на курсор не изменяет позицию курсора.

SEQUEL 2 обеспечивает специальное средство EXECUTE, которое позволяет основной программе поддерживать интерактивных пользователей. Предположим, что программа во время выполнения читает с терминала оператор SEQUEL, который должен быть выполнен. Она может вызвать выполнение этого оператора, как показано в Р5.

Р5. Вызвать System R для выполнения оператора SEQUEL 
в программную переменную QSTRING. 
EXECUTE QSTRING; 

Если интерактивный пользователь хочет выполнить запрос, основная программа, работающая с этим пользователем, должна иметь некоторые средства выборки результата запроса и его вывода на экран. Это сложно, так как программа не может знать заранее количество полей в результате запроса и их типы данных. Используемый метод комбинирует имя курсора с оператором EXECUTE, как показано в Р6.

P6. Прочитать запрос в QSTRING и выбрать и отобразить 
результат запроса. (Звездочки обозначают SEQUEL; остальное - PL/1.) 
DISPLAY("ENTER QUERY") REPLY(QSTRING); 
* LET C1 BE EXECUTE QSTRING; 
DESCRIBE C1 INTO <указатель-1>: 
/* Отформатировать буфер для одного кортежа и 
установить на него указатель-2 - объяснения приведены ниже. */
* OPEN C1; 
DO WHILE (CODE = OK); 
* FETCH C1 INTO <указатель-2>; 
/* Отобразить кортеж */ 
END; 
* CLOSE C1; 

В этой программе оператор LET C1 BE EXECUTE QSTRING связывает имя С1 с запросом, который во время выполнения будет находиться в QSTRING. Оператор DESCRIBE C1 возвращает описание числа полей и типов данных результата в массив, обозначенный как <указатель - 1>. Это позволит программе выделить пространство для буферов, чтобы хранить каждое поле результирующего кортежа. Затем программа образует массив указателей на эти буферы полей и устанавливает <указатель-2>, так чтобы он указывал на этот массив. Оператор OPEN C1 готовит систему к размещению первого кортежа. Затем каждый оператор FETCH C1 размещает один кортеж в указанных буферах. После выполнения оператора CLOSE C1 в QSTRING может быть прочитан новый запрос. Последовательное выполнение операторов DESCRIBE C1, OPEN C1 и FETCH C1 будет затем ссылаться на новый запрос.

При написании программы поддержки интерактивного пользователя программист должен разделять операторы запроса (например, SELECT * FROM EMP) и другие операторы, которые не возвращают никакого результата (например, DELETE EMP WHERE EMPNO = 505). Для этого проверяется первое слово входной строки. Все запросы начинаются со слова SELECT и обрабатываются с помощью

LET C1 BE EXECUTE QSTRING; 

Все операторы, не начинающиеся с SELECT, обрабатываются с помощью

EXECUTE QSTRING; 

Чтобы дать возможность программе сохранить результат запроса после его выполнения, расширен синтаксис оператора присваивания, так чтобы позволить присваивание активного множества курсора новому отношению, как показано в Р7.

Р7. Присвоить активное множество курсора С5 новому 
отношению EXEMPT, которое имеет столбцы EMPNO, NAME и JOB. 
ASSIGN TO EXEMPT(EMPNO,NAME,JOB):
  CURSOR C5; 

Программа на PL/1 со встроенными операторами SEQUEL передается прекомпилятору System R. Все операторы SEQUEL распознаются и заменяются вызовами модуля времени выполнения, который выполняет эти операторы. Где возможно, делается синтаксический разбор оператора SEQUEL и оптимальный путь доступа выбирается для него во время прекомпиляции. Когда это невозможно, как в случае EXECUTE, синтаксический разбор и выбор пути доступа выполняются во время выполнения.

Во время прекомпиляции проверка прав программы на выполнение различных действий выполняется по привилегиям пользователя, который компилирует программу. Если этот пользователь имеет необходимые права, он получает привилегию RUN для программы. Затем он может выполнять откомпилированную программу без дальнейшей проверки прав. Если автор программы включает опцию GRANT для всех привилегий, используемых программой, он получает привилегию RUN с опцией GRANT. Это позволяет ему предоставлять другим пользователям возможность выполнять его откомпилированную программу. Таким образом, пользователь может иметь привилегию RUN для программы, которая модифицирует зарплату, не имея при этом прав изменять зарплату каким-либо другим способом, кроме вызова этой программы.

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

Заключение

Мы описали подъязык данных SEQUEL 2, обеспечивающий согласованный, ориентированный на английские ключевые слова синтаксис для запросов, а также определения данных, манипулирования данными и контроля данных. Возможности SEQUEL 2 охватывают диапазон от средств запросов, в которых легко разобраться неспециалистам в обработке данных, до сложных средств, предназначенных для профессиональных программистов и администраторов баз данных. Мы продемонстрировали, как SEQUEL 2 может встраиваться в программу на PL/1 и как можно написать такую программу для поддержки SEQUEL 2 как автономного интерфейса для интерактивных пользователей. SEQUEL 2 является основным внешним интерфейсом экспериментальной системы баз данных System R. Хочется подчеркнуть, что System R и SEQUEL 2 - это части исследовательского проекта по управлению базами данных и не планируются как продукты IBM.

Приложение. Синтаксис SEQUEL 2

Здесь мы предлагаем упрощенную версию BNF-синтаксиса для SEQUEL 2. Акцент сделан на читаемости, а не на строгости, поэтому были допущены некоторые незначительные неоднозначности. Опущены некоторые возможности, которые присущи в особенности System R. Они относятся к массовой загрузке данных и управлению физическими сегментами. Кроме того, синтаксис допускает образование некоторых операторов, которые семантически бессмысленны. Более полный, но менее читаемый синтаксис используется в настоящее время в проекте System R.

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

statement ::= query
@Vtyagka:| dml-statement
| ddl-statement
| control-statement
| cursor-statement
dml-statement ::= assignment
@Vtyagka:| insertion
| deletion
| update
query ::= query-expr [ ORDER BY ord-spec-list ]
assignment ::= ASSIGN TO receiver : query-expr
@Vtyagka:| ASSIGN TO receiver : CURSOR cursor-name
receiver ::= table-name [ (field-name-list) ]
field-name-list ::= field-name
@Vtyagka:| field-name-list, field-name
insertion ::= INSERT INTO receiver : insert-spec
insert-spec ::= query-expr
@Vtyagka:| lit-tuple
deletion ::= DELETE table-name [ var-name ] [ where-clause ]
update ::= UPDATE table-name [ var-name ]
SET set-clause-list [ where-clause ]
where-clause ::= WHERE boolean
@Vtyagka:| WHERE CURRENT OF cursor-name
set-clause-list ::= set-clause
@Vtyagka:| set-clause-list, set-clause
set-clause ::= field-name = expr
@Vtyagka:| field-name = ( query-block )
query-expr ::= query-block
@Vtyagka:| query-expr set-op query-block
| ( query-expr )
set-op ::= INTERSECT | UNION | MINUS
query-block ::= select-clause [ INTO target-list ]
FROM from-list
[ WHERE boolean ]
[ GROUP BY field-spec-list
[ HAVING boolean ] ]
select-clause ::= SELECT [ UNIQUE ] sel-expr-list
@Vtyagka:| SELECT [ UNIQUE ] *
sel-expr-list ::= sel-expr
@Vtyagka:| sel-expr-list, sel-expr
sel-expr ::= expr
@Vtyagka:| var-name.*
| table-name.*
target-list ::= host-location
@Vtyagka:| target-list, host-location
from-list ::= table-name [ var-name ]
@Vtyagka:| from-list, table-name [ var-name ]
field-spec-list ::= field-spec
@Vtyagka:| field-spec-list, field-spec
ord-spec-list ::= field-spec [ direction ]
@Vtyagka:| ord-spec-list, field-spec [ direction ]
direction ::= ASC | DESC
boolean ::= boolean-term
@Vtyagka:| boolean OR boolean-term
boolean-term ::= boolean-factor
@Vtyagka:| boolean-term AND boolean-factor
boolean-factor ::= [ NOT ] boolean-primary
boolean-primary ::= predicate
@Vtyagka:| ( boolean )
predicate ::= expr comparison expr
@Vtyagka:| expr BETWEEN expr AND expr
| expr comparison table-spec
| < field-spec-list > = table-spec
| < field-spec-list> [ IS ] [ NOT ]
IN table-spec
@Vtyagka:| IF predicate THEN predicate
| SET ( field-spec-list ) comparison table-spec
| SET ( field-spec-list ) comparison
SET ( field-spec-list )
@Vtyagka:| table-spec comparison table-spec
table-spec ::= query-block
@Vtyagka:| ( query-expr )
| literal
expr ::= arith-term
@Vtyagka:| expr add-op arith-term
arith-term ::= arith-factor
@Vtyagka:| arith-term mult-op arith-factor
arith-factor ::= [ add-op ] primary
primary ::= [ OLD | NEW ] field-spec
@Vtyagka:| set-fn ( [ UNIQUE ] expr )
| COUNT ( * )
| constant
| ( expr )
field-spec ::= field-name
@Vtyagka:| table-name.field-name
| var-name.field-name
comparison ::= comp-op
@Vtyagka:| CONTAINS
| DOES NOT CONTAIN
| [ IS ] IN
| [ IS ] NOT IN
comp-op ::= = | ¬ = | > | >= | < | <=
add-op ::= + |-
mult-op ::= * | /
set-fn ::= AVG | MAX | MIN | SUM | COUNT
literal ::= ( lit-tuple-list )
@Vtyagka:| lit-tuple
| ( entry-list )
| constant
lit-tuple-list ::= lit-tuple
@Vtyagka:| lit-tuple-list, lit-tuple
lit-tuple ::= < entry-list >
entry-list ::= entry
@Vtyagka:| entry-list, entry
entry ::= [ constant ]
constant ::= quoted-string
@Vtyagka:| number
| host-location
| NULL
| USER
| DATE
| field-name OF CURSOR cursor-name
ON table-name
table-name ::= name
image-name ::= name
link-name ::= name
asrt-name ::= name
trig-name ::= name
name ::= [ creator. ] idetifier
creator ::= identifier
user-name ::= identifier
field-name ::= identifier
var-name ::= identifier
cursor-name ::= identifier
pointer ::= identifier
save-point-name ::= identifier
host-location ::= identifier [ : identifier ]
integer ::= number
ddl-statement ::= create-table
@Vtyagka:| expand-table
| create-image
| create-link
| define-view
| define-synonym
| drop
| comment
create-table ::= CREATE TABLE table-name
( field-defn-list )
field-defn-list ::= field-defn
@Vtyagka:| field-defn-list, field-defn
field-defn ::= field-name ( type [ , NONULL ] )
type ::= CHAR ( integer ) [ VAR ]
@Vtyagka:| INTEGER
| SMALLINT
| DECIMAL ( integer, [ integer ] )
| FLOAT
expand-table ::= EXPAND TABLE table-name ADD
COLUMN field-defn
create-image ::= CREATE [ image-mod-list ] IMAGE image-name
ON table-name ( ord-spec-list )
image-mod-list := image-mod
@Vtyagka:| image-mod-list image-mod
image-mod ::= UNIQUE
@Vtyagka:| CLUSTERING
create-link ::= CREATE [ CLUSTERING ] LINK link-name
FROM table-name ( field-name-list )
TO table-name ( field-name-list )
[ ORDER BY ord-spec-list ]
define-view ::= DEFINE VIEW table-name
[ ( filed-name-list ) ] AS query
define-synonym ::= DEFINE SYNONYM identifier AS table-name
drop ::= DROP system-entity name
comment ::= COMMENT ON system-entity name : quoted-string
@Vtyagka:| COMMENT ON COLUMN table-name.field-name : quoted-string
system-entity ::= TABLE | VIEW | ASSERTION | TRIGGER | IMAGE | LINK
control-statement ::= asrt-statement
@Vtyagka:| define-trigger
| grant
| revoke
| begin-trans
| end-trans
| save
| restore
asrt-statement ::= ASSERT asrt-name [ IMMEDIATE ]
[ ON asrt-condition ] : boolean
asrt-condition ::= action-list
@Vtyagka:| table-name [ var-name ]
action-list ::= action
@Vtyagka:| action-list, action
action ::= INSERTION OF table-name [ var-name ]
@Vtyagka:| DELETION OF table-name [ var-name ]
| UPDATE OF table-name [ var-name ]
[ ( filed-name-list ) ]
define-trigger ::= DEFINE TRIGGER trig-name
ON trig-condition : statement-list
trig-condition ::= action
@Vtyagka:| READ OF table-name [ var-name ]
statement-list := cond-statement
@Vtyagka:| statement-list; cond-statement
cond-statement ::= statement
@Vtyagka:| IF boolean THEN statement
grant ::= GRANT [ auth ] table-name TO user-list
[ WITH GRANT OPTION ]
auth ::= ALL RIGHTS ON
@Vtyagka:| operation-list ON
| ALL BUT operation-list ON
user-list ::= user-name
@Vtyagka:| user-list, user-name
| PUBLIC
operation-list ::= operation
@Vtyagka:| operation-list, operation
operation ::= READ
@Vtyagka:| INSERT
| DELETE
| UPDATE [ ( field-name-list ) ]
| EXPAND
| IMAGE
| LINK
| CONTROL
| RUN
revoke ::= REVOKE [ operation-list ON ] table-name FROM user-list
begin-trans ::= BEGIN TRANSACTION
end-trans ::= END TRANSACTION
save ::= SAVE save-point-name
restore ::= RESTORE [ save-point-name ]
cursor-statement ::= let
@Vtyagka:| open
| fetch
| close
| describe
| execute
let ::= LET cursor-name BE query
@Vtyagka:| LET cursor-name BE execute
open ::= OPEN cursor-name
fetch ::= FETCH cursor-name [ INTO pointer ]
close ::= CLOSE cursor-name
describe ::= DESCRIBE cursor-name INTO pointer
execute ::= EXECUTE host-location


Литература

  1. E.F.Codd, "A Relational Model of Data for Large Shared Data Banks", Communications ACM 13, 377 (июнь 1970). Есть русский перевод: Е.Ф.Кодд, "Реляционная модель данных для больших совместно используемых банков данных", СУБД N1, 1995.
  2. D.D.Chamberlin, R.F. Boyce, "SEQUEL : A Structured English Query Language", Proceedings of ACM-SIGFIDET Workshop, Ann Arbor, MI, май 1974.
  3. G.D.Held, M.R.Stonebraker, E.Wong, "INGRES : A Relational Data Base System", Proceedings of AFIPS National Computer Conference, Anaheim, CA, май 1975.
  4. M.M.Zloof, "Query By Example", Proceedings of AFIPS National Computer Conference, Anaheim, CA, май 1975.
  5. R.F.Boyce, D.D.Chamberlin, W.F.King, M.M.Hammer, "Specifying Queries as Relational Expressions: The SQUARE Data Sublanguage", Communications ACM 18, 621 ( Ноябрь 1975 ).
  6. P.Reisner, R.F.Boyce, D.D.Chamberlin, "Human Factors Evaluation of Two Data Base Query Languages: SQUARE and SEQUEL", Proceedings of AFIPS National ComputerConference, Anaheim, CA, май 1975.
  7. P.Reisner, "Use of Phychological Experimentation as an Aid to Development of a Query Language", Research Report RJ 1707, IBM Research Laboratory, San Jose, CA, январь 1976.
  8. M.M.Astrahan, et al., "System R: A Relational Approach to Data Base Management", ACM Transactions on Data Base Systems 1, 97 (июнь 1976).
  9. E.F.Codd, "Normalized Data Base Structure: A Brief Tutorial", Proceedings of ACM-SIGFIDET Workshop, San Diego, CA, Ноябрь 1971.
  10. R.Bayer, E.McCreight, "Organization and Maintenance of Large Ordered Indices", Proceedings of ACM-SIGFIDET Workshop, Houston, TX, ноябрь 1970.
  11. D.D.Chamberlin, J.N.Gray, L.L.Traiger, "Views, Authorization and Locking in a Relational Data Base System", Proceedings of AFIPS National Computer Conference, Anaheim, CA, май 1975.
  12. P.P.Griffits, B.W.Wade, "An Authorization Mechanizm for a Relational Data Base System", Proceedings of ACM SIGMOD Conference, Washington, DC, июнь 1976.
  13. K.P.Eswaran, D.D.Chamberlin, "Functional Specifications of a Sybsystem for Data Base Integrity", Proceedings of International Conference on Very Large Data Bases, Framingham, MA, сентябрь 1975.
  14. J.Mylopoulos, S.A.Schuster, D.Tsichrizis, "A Multi-level Relational System", Proceedings of AFIPS National Computer Conference, Anaheim, CA, май 1975.

Получена 25 мая 1976 года,
пересмотрена 6 июля 1976 года.