и T' должны быть типами;
T и T' должны быть типами; то есть каждый из них должен быть именованным множеством значений.
Каждое значение T' должно быть значением T; то есть множество значений, составляющих T', должно быть подмножеством множества значений, составляющих T (другими словами, если значение принадлежит типу T', то оно также должно принадлежать типу T). Более того, если T и T'
различны (см. IM-предписания 3 и 4), то должно существовать по крайней мере одно значение, которое принадлежит типу T
и не принадлежит типу T'.
T и T' не обязательно должны быть различны; то есть, каждый тип должен быть как подтипом, так и супертипом самого себя.
Если и только если типы T и T'
различны, то T' является собственным подтипом T, и T
является собственным супертипом T'.
Каждый подтип T' должен быть подтипом T. Каждый супертип T должен быть супертипом T'.
Если и только если T' является собственным подтипом T и не существует типа, который одновременно является собственным супертипом T' и собственным подтипом T, то T' является непосредственным подтипом T, а T является непосредственным супертипом T'. Тип, который не является непосредственным
подтипом какого-либо типа, является корневым
типом. Тип, который не является непосредственным
супертипом какого-либо типа, является листовым типом.
( Вариант, предполагающий множественное наследование )
Если типы T1 и T2 являются различными корневыми типами, то они должны быть непересекающимися; то есть никакое значение не должно одновременно принадлежать типу T1 и типу T2.
( Вариант, предполагающий множественное наследование )
Для каждого набора скалярных типов T1, T2, …, Tn (n>0) должен иметься общий подтип T' такой, что заданное значение принадлежит каждому из типов T1, T2, …, Tn, если и только если оно принадлежит типу T'.
Пусть скалярная переменная V относится к объявленному типу T. По причине возможности замены значений (см. IM-предписание 16) значение v, присвоенное V , в любой момент времени может принадлежать любому подтипу T' типа T как своему наиболее конкретному типу. Поэтому можно моделироватьV как именованный упорядоченный триплет вида <DT,MST,v>, где:
Именем триплета является имя переменной (в примере это V);
DT является именем объявленного типа переменной V;
MST является именем наиболее конкретного типа – называемого также текущим наиболее конкретным типом – (для)переменной V;
v является значением наиболее конкретного типа – текущим значением (для)переменной V.
Обозначения DT(V), MST(V), v(V) используются для ссылок на компоненты DT, MST и v этой модели скалярной переменной V
соответственно.
Далее, пусть X - скалярное выражение. Систему обозначений DT(V), MST(V), v(V) можно очевидным образом расширить для ссылок на объявленный тип DT(X), текущий наиболее конкретный тип MST(X) и текущее значение v(X) выражения X соответственно, где “объявленный тип” – это то, что разъяснялось в RM-предписании 3, и этот тип известен во время компиляции, а “текущий наиболее конкретный тип” и “текущее значение” относятся к результату вычисления X и поэтому в общем случае неизвестны до времени выполнения.
Пусть T - регулярный собственный супертип (см. IM-предписание 20), и пусть T' - непосредственный подтип T. Тогда в определении T' должно специфицироваться ограничение специализации SC, сформулированное в терминах T и такое, что значение типа T должно принадлежать типу T', если и только если оно удовлетворяет ограничению SC. Должно существовать по крайней мере одно значение типа T, которое не удовлетворяет ограничению SC.
Пусть X - выражение. Рассмотрим присваивание
V := X
;
(где V является переменной). DT(X) должно быть подтипом DT(V). Присваивание должно сделать MST(V) равным MST(X), а v(V) - равным v(X).
Рассмотрим сравнение на равенство
Y = X
(где Y и X являются выражениями). DT(X) и DT(Y) должны иметь общий супертип. Сравнение должно возвращать true, если MST(Y) равно MST(X) и v(Y) равно v(X), иначе - false.
Пусть rx и ry - отношения с общим атрибутом A, и пусть объявленные типы A в rx и ry
- это DT(Ax) и DT(Ay) соответственно. Рассмотрим соединение rx и ry ( обязательно по A, по крайней мере, частично). DT(X) и DT(Y) должны иметь общий супертип и, следовательно, обязательно общий наиболее конкретный супертип, скажем T. Тогда объявленным типом A в результате соединения должен быть тип T.
Аналогичные замечания относятся к объединению, пересечению и разности операций. То есть в каждом случае:
Соответствующие атрибуты операндов должны быть такими, что их объявленные типы имеют общий супертип;
Объявленный тип соответствующего атрибута результата должен быть соответствующим наиболее конкретным общим супертипом.
Для каждого типа T должна поддерживаться операция в форме
TREAT_DOWN_AS_T ( X )
(или ее логический эквивалент), где X является выражением. T должен быть подтипом DT(X) и MST(X) должен быть подтипом T. Такие операции обобщенно называются операциями “TREAT DOWN”; их семантика такова:
Если вызов TREAT DOWN появляется в позиции “источника” (в частности, в правой части присваивания), объявленный тип этого вызова должен быть T, и вызов должен вырабатывать результат, скажем r, с MST(r) равным MST(X) и v(r) равным v(X).
Если вызов TREAT DOWN появляется в позиции “цели” (в частности, в левой части присваивания), этот вызов должен действовать как псевдопеременная, что означает, что он должен реально назначать
свой аргумент X (точнее, он должен назначать версию X, для которой DT(X) равно T, но MST(X) и v(X) неизменны). Аргумент X должен быть указан именно как переменная, а не как произвольное выражение.
( Вариант, предполагающий множественное наследование )
Для каждого типа T, должна поддерживаться логическая операция вида
IS_T ( X )
(или ее логический эквивалент), где X - выражение. DT(X) и T
должны иметь общий подтип. Эта операция должна возвращать true, если v(X) принадлежит типу T, и false в противном случае.
Пусть Op - операция только чтения, пусть P - параметр Op, и пусть T - объявленный тип для P. Тогда должно допускаться, чтобы объявленный тип выражения аргумента (и следовательно, тем более, наиболее конкретный тип значения аргумента), соответствующего параметру P в вызове Op, был любым подтипом T' типа T. Другими словами, операция только чтения Op применяется к значениям типа T и поэтому, обязательно, к значениям типа T' – Принцип Наследования Операций (Только Чтения). Из этого следует, что такие операции являются полиморфными, поскольку они применимы к значениям нескольких различным типам – Принцип Полиморфизма Операций (Только Чтения). И далее из этого следует, что везде, где допускается значение типа T, должно также допускаться значение любого собственного подтипа T – Принцип Возможности Замены (Значений).
Для каждой заданной операции Op должны иметься:
Ровно одна спецификационная сигнатура, состоящая из имени операции Op вместе с объявленными типами параметров в порядке указания параметров (и объявленным типом результата, если он существует), как это указывается потенциальным пользователям Op.
Набор версионных сигнатур, по одной для каждой реализационной версии Op; каждая версионная сигнатура состоит из имени операции Op (и, возможно, имени версии) вместе с объявленными типами параметров в порядке указания параметров (и объявленным типом результата, если он существует), который определяется для этой версии.
Набор сигнатур вызова, по одной для каждой возможной комбинации наиболее конкретных типов аргументов для вызова Op; каждая сигнатура вызова состоит из имени операции Op вместе с соответствующей упорядоченной комбинацией наиболее конкретных типов аргументов.
Если действительно существует несколько версий Op, то все эти версии фактически должны реализовывать одну и ту же семантику.
Пусть Op - операция обновления, и пусть P - параметр Op, который не является предметом обновления. Тогда Op
должна вести себя как операция только чтения, насколько это относится к P, и, следовательно, все аспекты IM-предписания 16 должны быть применимы.
Пусть Op - операция обновления, пусть P
- параметр Op, который является предметом обновления, и пусть T
является объявленным типом для P. Тогда неясно, должно ли допускаться, чтобы объявленный тип (и, следовательно, тем более, текущий наиболее конкретный тип) аргумента-переменной, соответствующего параметру P в некотором вызове Op, был собственным подтипом типа T (в некоторых случаях это должно допускаться, а в некоторых - нет). Из этого следует, что для каждой такой операции обновления Op и для каждого параметра P операции Op, который является предметом обновления, необходимо явно установить, для каких подтипов объявленного типа T параметра P операция Op должна наследоваться – Принцип Наследования Операций (Обновления). (И если операция обновления Op не наследуется таким образом типом T', она не должна наследоваться и никаким подтипом типа T'.) Таким образом, операции обновления должны быть только условно полиморфными – Принцип Полиморфизма Операций (Обновления). Если Op является операцией обновления, P - параметр Op, который является предметом обновления, и T'
является таким подтипом объявленного типа T
для P, что для T' наследуется Op, то по определению должно быть можно вызывать Op с аргументом-переменной, соответствующим параметру P, когда этот аргумент принадлежит объявленному типу T' – Принцип Возможности Замены (Переменных).
Объединенный тип (union type) - это такой тип T, что не существует значения, которое принадлежит типу T и не принадлежит какому-либо собственному подтипу T (то есть не существует такого значения v, что MST(v) есть T). Фиктивный тип (dummy type) - это объединенный тип, который не имеет никакого объявленного возможного представления (и, следовательно, никакого селектора); должно разрешаться, чтобы данный объединенный тип был фиктивным типом, если и только если этот объединенный тип не имеет никакого регулярного непосредственного супертипа (где регулярный тип - это тип, который не является фиктивным типом). Более того,
Концептуально, существует ровно один фиктивный тип, alpha, который содержит все скалярные значения. Тип alpha - это максимальный тип
по отношению к каждому скалярному типу; по определению он не имеет никакого объявленного возможного представления и никаких собственных подтипов.
Если и только если мы ослабляем наше допущение об одиночном наследовании, то концептуально также существует ровно один фиктивный тип, omega, который не содержит никаких скалярных значений вообще (то есть является пустым). Тип omega - это минимальный тип по отношению к каждому скалярному типу; по определению он не имеет никакого объявленного возможного представления и никаких собственных подтипов.
Пусть типы T и T' оба являются типами кортежа или оба являются типами отношения с заголовками
{ <A1,T1>, <A2,T2>, …, <An,Tn> }
{ <A1,T1'>, <A2,T2'>, …, <An,Tn'> }
соответственно. Тогда тип T' является подтипом
типа T (или, эквивалентно, тип T является супертипом типа T'), если и только если для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti (или, эквивалентно, тип Ti является супертипом типа Ti').
Пусть H - заголовок кортежа или заголовок отношения, определенный следующим образом:
{ <A1,T1>, <A2,T2>, …, <An,Tn> }
Тогда:
a. кортеж t соответствует заголовку H, если и только если t имеет вид
{ <A1,T1',v1>, <A2,T2',v2>, …, <An,Tn,vn> }
где для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti и vi - значение типа Ti'.
c. отношение r соответствует заголовку H,
если и только если r состоит из заголовка и тела, где:
· Заголовок r имеет вид
{ <A1,T1'>, <A2,T2'>, …, <An,Tn'> }
где для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti;
· Тело r - это множество кортежей, которые все соответствуют заголовку r.
Пусть все три типа T, T_alpha, и T_omega - это типы кортежей или типы отношений с заголовками
{ <A1,T1>, <A2,T2>, …, <An,Tn> }
{ <A1,T1_alpha>, <A2,T2_alpha>, …, <An,Tn_alpha> }
{ <A1,T1_omega>, <A2,T2_omega>, …, <An,Tn_omega> }
соответственно. Тогда типы T_alpha и T_omega
являются максимальным типом по отношению к типу T и минимальным типом по отношению к типу T соответственно, если и только если для всех i (i
= 1, 2, …, n) тип Ti_alpha является максимальным типом по отношению к типу Ti и Ti_omega является минимальным типом по отношению к типу Ti.
Пусть H - заголовок кортежа или заголовок отношения, определенный следующим образом:
{ <A1,T1>, <A2,T2>, …, <An,Tn> }
Тогда:
Если t - кортеж, соответствующий H – в том смысле, что t имеет вид
{ <A1,T1',v1>, <A2,T2',v2>, …, <An,Tn’,vn> }
где для всех i (i = 1, 2, …, n) тип Ti' является подтипом типа Ti',
и vi - это значение типа Ti', то наиболее конкретным типом t
является
TUPLE { <A1 ,MST1>, <A2, MST2>, …, <An MSTn> }
где для всех i (i = 1, 2, …, n) тип MSTi является наиболее конкретным типом значения vi.
Если r - отношение, соответствующее H – в том смысле, что тело r является множеством кортежей, каждый из которых имеет в качестве своего наиболее конкретного типа тип, являющийся подтипом типа TUPLE{H}, и в том смысле, кроме того, что каждый кортеж можно считать без потери общности имеющим вид
{ <A1,T1',v1>, <A2,T2',v2>, …, <An,Tn’,vn> }
где для всех i (i = 1, 2, …, n), тип Ti' является подтипом типа Ti
и наиболее конкретным типом значения vi
(отметим, что разные кортежи в теле r
будут в общем случае принадлежать разным наиболее конкретным типам; таким образом, тип Ti' различается для разных кортежей в теле r) – то наиболее конкретным типом r является
RELATION { <A1, MST1>, <A2, MST2>, …, <An, MSTn> }
где для всех i (i = 1, 2, …, n), тип MSTi является наиболее конкретным общим супертипом этих наиболее конкретных типов Ti', взятых для всех кортежей в теле r.
Пусть переменная (кортежа или отношения) V имеет объявленный тип T, и пусть заголовок T имеет атрибуты A1,A2, …, An. Тогда можно моделировать V как множество именованных упорядоченных триплетов вида <DTi,MSTi,vi>, где:
Имя каждой тройки является именем соответствующего атрибута.
DTi является именем объявленного типа атрибута Ai.
MSTi является именем наиболее конкретного типа – называемого также как текущим наиболее конкретным типом – (для) атрибута Ai. (Если V - переменная отношения, то наиболее конкретный тип Ai
определяется как наиболее конкретный общий супертип наиболее конкретных типов m значений в vi – см. объяснение vi
ниже.)
Если V - переменная кортежа, то vi - это значение наиболее конкретного типа MSTi
– текущее значение (для) атрибута Ai. Если V - переменная отношения, то пусть тело текущего значения V состоит из m кортежей; пометим эти кортежи (в некоторой произвольной последовательности) как “tuple 1”, “tuple 2”, … “tuple m”; тогда vi является последовательностью из m значений (не обязательно различных), являющихся значениями Ai из tuple 1, tuple 2, … tuple m
(в таком порядке); отметим, что все эти значения принадлежат типу MSTi.
Обозначения DT(Ai), MST(Ai), v(Ai) используются для ссылок на компоненты DTi, MSTi, vi соответственно атрибута Ai этой модели переменной кортежа или отношения V. Мы также используем обозначения DT(V), MST(V), для ссылки на объявленный тип целиком, текущий наиболее конкретный тип целиком и текущее значение целиком соответственно переменной кортежа или отношения V. Отметим, что фактически MSTi(Ai) подразумевается v(Ai), и MST(V) подразумевается v(V).
Пусть теперь X - выражение кортежей или отношений. Только что введенные обозначения Dti(V), MSTi(V),vi(V) можно очевидным образом расширить для ссылки на объявленный тип Dti(X), текущий наиболее конкретный тип MSTi(X)и текущее значение vi(X) соответственно компонентов Dti, MSTi, vi атрибута Ai
выражения кортежей или отношений X.
для краткости тип) интерпретируются как
Термины домен и тип данных ( для краткости тип) интерпретируются как синонимичные и взаимозаменяемые. В том же самом смысле иногда используется термин объектный класс, но Д&Д не используют этот термин.
Д&Д обобщенно называют значения домена скалярными значениями (для краткости скалярами). Тем самым явно допускаются “скалярные” значения произвольной сложности. Например, при определенных обстоятельствах массив стеков списков … и т.д. может рассматриваться как скалярное значение.
Логические различия и логические ошибки, концептуальная целостность
Наиболее важным принципом, которым руководствовались Д&Д на протяжении своей работы над Третьим Манифестом, является следующий: все логические различия являются большими различиями. Основой любой формальной системы является логика. Поэтому во всем, что относится к формальным системам вообще и что касается Манифеста в частности, различия, которые по своей природе являются логическими, очень важны, и на них следует обращать особое внимание. Из этой максимы следует, что все логические ошибки являются большими ошибками.
Принцип концептуальной целостности, который Д&Дтакже относят к числу основополагающих, трактуется в том смысле, что с целью поддержания интеграции концепций необходимо поставить некоторые концепции на первое место. Рассматриваемые концепции должны быть тщательно отобраны, их должно быть как можно меньше, они должны быть согласованы и приемлемы по своей природе.
Модель наследования
В Третьем манифесте представлена хорошо проработанная, концептуально согласованная модель наследования, базирующаяся на концепции специализации путем ограничения. Д&Д сначала разрабатывают теорию одиночного наследования для скалярных типов, затем развивают ее для множественного наследования скалярных типов и, наконец, обобщают до случая множественного наследования типов кортежей и ограничений. В этой статье мы не можем полностью (хотя бы кратко) описать модель. Ограничимся изложением предписаний (IM -предписаний, IM от Inherinence Model ).
C имволы T и T' используются далее для обозначения пары типов, таких что T' является подтипом T (или, что эквивалентно, T является супертипом для T'). В общем случае эти типы могут быть не только скалярными.
Некоторые ключевые логические различия
Существуют некоторые логические различия, которые имеют отношение ко всему дальнейшему – это различия между (a) моделью и реализацией, (b) значением и переменной, и (c) значением, видом и кодировкой.
Различие между моделью и реализацией определяется следующим образом:
Модель – это абстрактное, замкнутое, логическое определение объектов, операций и т.д., совместно представляющих абстрактную машину, с которой взаимодействуют пользователи.
Реализация данной модели – это физическая реализация компонентов модели на реальной компьютерной системе.
Различие между моделью и реализацией в действительности является важным частным случаем различия между логическим и физическим аспектами системы. Во всем Манифесте и во всей книге Д&Д имеют дело с абстрактной моделью, а не с вопросами реализации. (Под “реализацией” понимается реализация СУБД, а не некоторого приложения, работающего под управлением этой системы.)
Второе логическое различие – это различие между значениями
и переменными (под переменной мы понимаем переменную в обычном смысле языка программирования). Используются следующие определения:
Значение – это “индивидуальная константа” (например, индивидуальная константа “3”).113
У значения нет позиции во времени и пространстве. Однако значения могут быть представлены в памяти (посредством некоторой кодировки), и у таких представлений (видов) имеется позиция во времени и пространстве: любое число различных переменных может иметь одно и то же значение одновременно или в разное время. По определению значение невозможно модифицировать.
Переменная – это контейнер вида значения. Переменная имеет позицию во времени и пространстве. Переменные, в отличие от значений, можно модифицировать; т.е. текущее значение данной переменной можно заменить другим значением, возможно, отличным от исходного.
Значения могут быть произвольно сложными; например, значение может быть массивом, стеком, списком, отношением, геометрической точкой и т.д. Аналогичное замечание относятся и к переменным.
Общие принципы
Здесь мы опираемся на материал первых двух глав [20]. Назначение материала состоит в том, чтобы ввести некоторую концептуальную базу для дальнейшего изложения.
Неявные преобразования типов препятствовали бы
В языке D следует поддерживать некоторый уровень наследования типов (см. OO-предписания 2 и 3). В соответствии с этим суждением в D не следует поддерживать принуждения (т.е. неявные преобразования типов).
Комментарии
Неявные преобразования типов препятствовали бы достижению цели заменяемости; отмеченные параметры вводили бы искусственную и не необходимую степень асимметрии.
Определениям операций следует быть логически отличимыми от определений типов их параметров и/или результатов; эти определения не следует связывать в один узел (хотя селекторы и операции, требуемые в RM-предписании 5 можно рассматривать как исключения по отношению к этому суждению).112
Следует поддерживать генераторы типов “коллекций”, такие как LIST, ARRAY и SET, распространенные в языках с развитыми системами типов.
Для любого генератора типа коллекции С, отличного от RELATION, следует обеспечить операцию преобразования (скажем, C2R) для преобразования значений заданного типа, сгенерированного C, в отношения, и обратную операцию (скажем, R2C) такую, что:
C2R(R2C(r)) = r для любого выразимого r;
R2C(C2R(c)) = c для любого выразимого значения c типа C.
должно быть возможно выполнять проверку
В D должна допускаться проверка типов во время компиляции.
Комментарии
В этом предписании имеется в виду, что – насколько это осуществимо – должно быть возможно выполнять проверку на стадии компиляции, чтобы на стадии исполнения не могли происходить какие-либо ошибки типов.
Если в языке D поддерживается наследование типов, то такая поддержка должна подчиняться модели наследования, определенной в Части IV этой книги.108
D должен быть вычислительно полным. То есть в D могут поддерживаться ( но не должны требоваться) вызовы из так называемых “основных программ”, написанных на языках, отличных от D. Аналогично, в D может поддерживаться (но не должно требоваться) использование других языков программирования для реализации определяемых пользователями операций.
Инициация транзакций должны производиться только посредством явного выполнения операции “begin transaction”. Завершение транзакции должно производиться только посредством выполнения операций “commit” или “rollback”; фиксация всегда должна быть явной, а откат может быть неявным (в том и только в том случае, когда транзакция завершается неуспешно не по своей вине). Если транзакция TX
завершается фиксацией (“нормальное завершение”), то изменения, произведенные TX в соответствующей базе данных, должны быть зафиксированы. Если транзакция TX
завершается откатом (“аварийное завершение”), то изменения, произведенные транзакцией TX в соответствующей базе данных, должны быть аннулированы.
В D должны поддерживаться вложенные транзакции, т.е. должна допускаться инициация транзакцией-предком TX транзакции- потомка TX’ до завершения транзакции TX. При этом:
TX и TX’
должны взаимодействовать с одной и той же базой данных (что в действительности требуется RM-предписанием 17);
Потребуется ли задержка выполнения TX на время выполнения TX’, должно определяться в зависимости от реализации. Однако TX
не должна завершаться до завершения TX’; другими словами, TX’ должна полностью содержаться в TX.
Откат TX должен включать откат TX’, даже если TX’ завершилась фиксацией. Другими словами, “фиксация” всегда интерпретируется в контексте предка (если он существует) и может быть отменена транзакцией-предком (опять же, если она существует).
Пусть AggOp – агрегатная
операция, такая как SUM. Если аргумент AggOp
является пустым, то:
Если AggOp является сокращенной формой некоторой итеративной скалярной бинарной операции Op (в случае SUM это операция “+”), и если для Op существует начальное значение (0 в случае SUM), то результатом вызова AggOp должно быть это начальное значение.
В противном случае результат вызова AggOp s должен быть неопределенным.
Категорически отвергается равенство вида
Переменные relvar – это не домены.
Комментарии
Категорически отвергается равенство вида “отношение = объектный класс” (более точно, равенство “relvar = объектный класс”)109.
Никакая relvar базы данных не должна содержать атрибут типа pointer (указатель ).110
Комментарии
Отвергается идея “объектных идентификаторов”. Как следствие этого, отвергаются (a ) идея о том, что такие идентификаторы могли бы использоваться в “объектах” для совместного использования “подобъектов”; (b ) идея о том, что пользователи могли бы быть обязаны “разыменовывать” такие идентификаторы (явно или неявно), чтобы получать значения.
Также отвергается идея “идентификаторов кортежей” (как кажется, некоторые авторы отождествляют идентификаторы кортежей и идентификаторы объектов).
Это запрещение не препятствует тому, чтобы объекты вне базы данных обладали идентификаторами, которые являются “каким-либо образом отличными” от самих объектов. Оно не препятствует также появлению таких идентификаторов в базе данных. (Термин “объект” используется здесь в его общем смысле, а не в специализированном смысле объектно-ориентированного подхода.) Поэтому, например, домен имен файлов базовой операционной системы является допустимым доменом.
Основы будущих систем баз данных
В качестве названия этого раздела была выбрана часть названия второго издания книги Дейта и Дарвена “Основы будущих систем баз данных: третий манифест” [20]. Этот выбор названия раздела не случаен, потому что раздел базируется на этой книге – она для него означает примерно то же, что книги [5] и [13] для подразделов 2.2 и 3.2 соответственно.
Прежде, чем переходить к основному материалу раздела, кратко представим содержание книги [20]. Прежде всего, заметим, что это второе издание, вышедшее в свет в 2000 г. Первое издание было опубликовано в 1998 г. под названием “Основы объектно/реляционных баз данных” [19]. Вот что пишут Д&Д по поводу изменения названия в предисловии ко второму изданию [20]: “Название первой редакции характеризовало Манифест как “основание объектно/реляционных баз данных”. Хотя эта характеристика была точной, она не была достаточной. Теперь мы считаем Манифест (как, впрочем, было всегда) основанием будущих баз данных вообще – включая, например, базы данных, содержащие темпоральные данные, и базы данных, используемые в связи с World Wide Wed .”
Однако, как кажется, более вероятными причинами для смены названия были следующие обстоятельства:
Название первого издания могло вводить в заблуждение читателей, не слишком хорошо знакомых с подходом Д&Д. Термин “объектно-реляционные системы баз данных” достаточно давно закрепился за технологией, следующей идеям Второго манифеста и реализованной в разных формах в продуктах Informix , Oracle и IBM . Видимо, при выборе названия для первого издания своей книги Д&Д стремились подчеркнуть, что идеи именно Третьего манифеста могут привести к достижению тех целей, которые ставили перед собой создатели Второго манифеста.
Но независимо от того, присутствие слова “объектно” в названии первого издания книги противоречило явственно высказываемому Д&Д отношению к объектной технологии в области баз данных. Д&Д постоянно подчеркивают путаницу и туманность, связанные с использованием термина “объект” в “объектно-ориентированном мире”.
Сами они используют ( или стремятся использовать) это слово только в неформальном смысле. Но в этом случае неясно, как следует трактовать названием первого издания. Основы чего предлагают авторы?
Конечно, второе издание [20] появилось так скоро после выхода в свет первого издания не только и не столько потому, что авторы решили изменить название. В первом издании была недостаточно доработана часть книги, посвященная наследованию типов. За два года после выхода в свет этого издания Д&Д сумели построить законченную модель наследования, и именно желание представить полный вариант своих предложений побудило авторов к быстрым подготовке и публикации второго издания книги.
Второе издание [20] имеет следующую структуру. Основной текст книги разделен на четыре части: вступление, формальные спецификации, неформальные обсуждения и объяснения, подтипизация и наследование.
Первая часть книги состоит из двух вводных глав, написанных без привлечения каких-либо формализмов. В главе 1 содержится базовая информация, поясняющая некоторые основополагающие идеи, лежащие в основе книги. В частности, обсуждаются ключевые логические различия между понятиями м одели и реализации; значения и переменной; значения, вида и кодировки
значения. Глава 2 состоит из неформального обсуждения двух возможных подходов к ключевому вопросу интеграции объектов и отношений (что соответствует понятию объектного класса в реляционной модели данных?). Демонстрируется, что один из этих подходов является правильным, а другой – ложным.
Вторая часть
книги носит наиболее формальный характер. В главе 3 приводится сам Третий манифест в том виде, как мы изложили его в подразделе 4.1. В главе 3 содержится определение новой реляционной алгебры (“A ”). В главе 4 определяется язык Tutorial D . Этот язык основывается на принципах, заложенных в Манифесте, и на алгебре A . Tutorial D служит основой для примеров в следующих главах книги. Он также позволяет судить о том, что могла бы представлять собой на практике СУБД, поддерживающая идеи Манифеста.
Третья часть
представляет собой реальную сердцевину книги. Она состоит из шести глав, по одной для каждого из шести разделов Манифеста, как он определяется в главе 3. Эта часть, по существу, является сильно расширенным вариантом неформальных комментариев к предписаниям, запретам и очень строгим суждениям Третьего манифеста
Четвертая часть книги играет для подтипизации и наследования ту же роль, что первые три части . Так, глава 12
соответствует первой части (она содержит общее введение в тему ); глава 13 соответствует второй части (она содержит формальные определения); а главы 14, 15 и 16 соответствуют третьей части (они содержат расширенные, но неформальные пояснения и обсуждения этих формальных определений). Точнее, в главе 14
рассматривается только одиночное наследование при наличии скалярных типов; в главе 15 идеи, обсуждаемые в главе 14, расширяются для включения поддержки множественного наследования; в главе 16 в расчет принимаются также типы кортежей и отношений.
В дополнение к перечисленным главам в книге содержится одиннадцать приложений.
В приложении A определяется альтернативный вариант Tutorial D , основанный на реляционном исчислении, а не на реляционной алгебре.
Приложение B посвящено обсуждению “двух больших заблуждений” (приравнивание отношений и объектных классови смешение указателей и отношений).
В приложении C обсуждается “дилемма проектирования” (как лучше проектировать базу данных – в терминах структуры отношений или в терминах определяемых пользователем типов данных?).
В приложении D рассматриваются вопросы единиц измерения в контексте определения типов данных.
Приложение E посвящается критике применяемого в объектно-реляционном подходе механизма “супертаблиц и подтаблиц”.
В приложении F продолжается начатое в четвертой части книги обсуждение проблем, связанных с изменением семантики операций при определении типов данных с использованием наследования.
В приложении G критикуются подходы к наследованию типов, не основанные на специализации путем ограничения.
В приложении H подход Третьего манифеста сравнивается с подходом стандарта SQL :1999.
Аналогичное сравнение с подходом ODMG содержится в приложении I .
В приложении J приводится текст интервью, данного Д&Д по поводу Третьего манифеста в 1994 г.
В заключительном приложении (Приложении K) приводится аннотированный и согласованный список публикаций, используемых во всей книге.
В этом подразделе мы остановимся на следующих темах, обсуждаемых в книге [20]:
общие принципы; система типов; модель наследования и подтипизации.
Первая реализация
Первый коммерчески доступный продукт, основанный на идеях Третьего манифеста, был выпущен около двух лет назад компанией Alphora ( ). Продукт получил название Dataphor .
Базовым компонентов Dataphor является Data Access Engine (DAE ), который представляет собой истинную ( т. е. соответствующуютребованиям Третьего манифеста) системуреляционныхбазданных. Полная и точная реализация реляционной модели в DAE обеспечивает следующие возможности:
Полная целостность данных. Полностью поддерживается каждое правило приложения, что обеспечивает, помимо технической согласованности данных, гарантию соответствия деятельности компании установленным требованиям закона.
“Сложные” типы данных. Обеспечивается возможность определения типов данных разработчиками, и эти типы данных равноправны со встроенными типами.
Работа с отсутствующей информации без привлечения неопределенных значений и трехзначной логики.
Обновляемые представления без ограничений, свойственных SQL .
Разработан и реализован язык D 4, обладающий следующими особенностями:
Для выражения запросов используется алгебраический подход.
Запросы, адресуемые к сложным данным, формулируются более точно, чем на языке SQL .
То же касается сложных операций обновления.
Язык обладает вычислительной полнотой.
Язык претендует на то, чтобы стать открытым стандартом, заменяющим SQL .
Не ясно, поддерживается ли в D 4 (и в DAE ) механизм наследования типов. Компания и разработанная ей система очень молоды, и перспективы успеха на рынке более чем неочевидны.
По поводу приведенных примеров следует сделать несколько замечаний:
С уществует существенное логическое различие между (a ) формальными операндами, или параметрами, в терминах которых определяется данная операция и (b ) реальными операндами, или аргументами, которые передаются любому вызову этой операции. (Эта разница становится особенно значительной, если поддерживается наследование типов.)
Объявленный тип каждого аргумента должен быть в точности тем же, что и объявленный тип соответствующего параметра (исключения возможны, если поддерживается наследование типов).
Важное логическое различие имеется между операциями обновления и операциями только чтения. Операции обновления применяются к переменным, а не к значениям. Следовательно, операции только чтения применяются к значениям (в частности, они применимы к значениям, которые являются текущими значениями переменных); операции обновления применяются именно к переменным.
Когда вызывается операция обновления, аргументы, соответствующие параметрам, которые являются предметом обновления (аргументы, соответствующие параметрам, указанным в спецификации UPDATES ), должны быть заданы как переменные, а не как произвольные выражения, и при вызове операции этим переменным потенциально присваиваются значения. Другие аргументы таких вызовов (и все аргументы вызовов операций только чтения) могут быть специфицированы как произвольные выражения.
Аргументы, которые соответствуют параметрам, являющимся предметом обновления, всегда передаются по ссылке, из чего следует, что операции над этими параметрами являются в действительности операциями над соответствующими аргументами (в частности, присваивание значения такому параметру в действительности присваивает значение соответствующему аргументу). Все другие аргументы передаются по значению, и операции над соответствующими параметрами в действительности являются операциями над “фиктивными” (создаваемыми системой) аргументами, которым задаются те же значения, что и подлинным аргументам.
Поскольку вызов скалярной операции только чтения возвращает скалярный результат, такой вызов представляет собой частный случай скалярного выражения.
Он может появиться везде, где может появиться вызов скалярного селектора. Таким образом, посредством вложения вызовов скалярных операций только чтения может быть построено скалярное выражение любой сложности.
Поскольку системе известны объявленные типы всех параметров и всех результатов скалярных операций, система знает, какие скалярные выражения допустимы (т.е. не приводят к возникновению ошибок, связанных с типами). Система знает также тип результата каждого такого допустимого выражения. Такой тип называется объявленным типом скалярного выражения.
Поскольку вызов операции обновления не возвращает результата, такой вызов стоит рассматривать как оператор, а не как выражение. В частности, он не может выступать в качестве аргумента для других вызовов операций.
Как отмечалось ранее, в определении любого скалярного типа должно указываться по крайней мере одно объявленное возможное представление для значений этого скалярного типа (и при таком заданном скалярном типе T и таком возможном представлении PR каждое значение типа T должно быть представимо посредством PR ).118Объявление возможного представления автоматически приводит в действие поддержку соответствующего селектора (и нельзя обеспечить селекторы никаким другим способом). Следовательно, селекторы и возможные представления находятся во взаимно однозначном соответствии друг с другом (параметры селекторов и компоненты возможных представлений находятся также во взаимно однозначном соответствии). Поэтому можно принять соглашение о задании селектору и соответствующему возможному представлению одного и того же имени (хотя они являются логически различными понятиями).
Следует подчеркнуть различия между вызовами селекторов вообще и литералами в частности. Коротко говоря, все литералы являются вызовами селекторов, но не все вызовы селекторов являются литералами. Вызов селектора является литералом тогда и только тогда, когда его аргументы (если они есть) в свою очередь являются литералами. Таким образом, литерал является символом, который обозначает некоторое фиксированное значение, которое определяется на все времена конкретным рассматриваемым символом.
Объявленный тип этого символа ( который является, конечно, частным случаем выражения) также определяется самим.
Вернемся к примеру определяемого пользователем типа POINT , чтобы обсудить вопросы определения
и реализации типов. Повторим в упрощенном виде определение этого типа:
TYPE POINT
POSSREP POINT { X LENGTH, Y LENGTH }
POSSREP POLAR { R LENGTH, THETA ANGLE } ;
В данном примере в определении типаспецифицированы два объявленных возможных представления – POINT и POLAR . Следовательно, будут существовать две соответствующие операции выбора: POINT , которая позволяет пользователю задавать декартовы координаты X и Y как два значения типа LENGTH и возвращает соответствующее значение типа POINT , и POLAR , которая позволяет пользователю задавать полярные координаты R и THETA как значения типов LENGTH и ANGLE соответственно и возвращает соответствующее значение типа POINT .
Предположим, что представление с декартовыми координатами на самом деле является реальным. Тогда в системе будут поддерживаться высоко защищенные операции, не входящие в D , которые раскрывают это реальное представление, и реализатор типа будет использовать эти операции для реализации требуемых селекторов POINT и POLAR . Вот, например, возможная реализация (псевдокод) для селектора POINT :
OPERATOR POINT ( X LENGTH, Y LENGTH ) RETURNS POINT ;
BEGIN ;
VAR P POINT ;
P.X := X ; /* assign to actual representation */
P.Y := Y ; /* assign to actual representation */
RETURN P ;
END ;
END OPERATOR ;
“Высоко защищенные операции, не входящие в D ” представлены в приведенном коде посредством точечной нотации. Селектор POLAR также мог бы быть реализован “вне среды D ” (снова псевдокод):
OPERATOR POLAR ( R LENGTH, THETA ANGLE ) RETURNS POINT ;
BEGIN ;
VAR P POINT ;
P.X := R * COS ( THETA ) ;
P.Y := R * SIN ( THETA ) ;
RETURN P ;
END ;
END OPERATOR ;
Но селектор POLAR , возможно, менее эффективно мог бы быть реализован в терминах селектора POINT :
OPERATOR POLAR ( R LENGTH, THETA ANGLE ) RETURNS POINT ;
RETURN POINT ( R * COS ( THETA ), SIN ( THETA ) ) ;
END OPERATOR ;
Из всего этого следует, что реализаторы типа(но не определители типа и, конечно, не пользователи типа) должны на самом деле знать реальные представления.
Пусть PR - это возможное представление скалярного типа T , и пусть у PR имеются компоненты C 1 , C 2 , …, Cn . Определим THE _ C 1 , THE _ C 2 , …, THE _ Cn как семейство операций, таких что для каждогоi (i = 1, 2, …, n ), операция THE _ Ci обладает следующими свойствами:
Ее единственный параметр имеет тип T .
Если ссылка на операцию, появляется в позиции “источника” (в частности, в левой части присвоения), то операция возвращает компонент Ci своего аргумента. (Точнее, она возвращает значение компонента Ci возможного представления PR ( v ) значения своего аргумента v .)
Если ссылка на операцию, появляется в позиции “цели” (в частности, слева от присвоения), то:
Аргумент должен быть явно указан как переменная, а не произвольное выражение.
Ссылка действует как ссылка на псевдопеременную, и это означает, что она реально обозначает компонент Ci этого аргумента, а не только возвращает значение его значение. (Точнее, она обозначает компонент Ci возможного представления PR ( V ) аргумента-переменной V .)
Несколько примеров :
TYPE TEMPERATURE POSSREP CELSIUS { C RATIONAL } ;
VAR TEMP TEMPERATURE ;
VAR CEL RATIONAL ;
CEL := THE_C ( TEMP ) ;
THE_C ( TEMP ) := CEL ;
В первом присваивании температура, измеренная в градусах Цельсия, которая является текущим значением переменной TEMP типа TEMPERATURE , присваивается переменной CEL типа RATIONAL ; во втором – текущее значение переменной CEL типа RATIONAL , рассматриваемое как температура в градусах Цельсия, используется для обновления переменной TEMP типа TEMPERATURE . Операция THE _ C фактически раскрывает возможное представление температуры посредством “градусов Цельсия” как для целей обновления, так и для целей только чтения.
Но это возможное представление не обязательно является реальным представлением; например, температуру можно было бы представлять в градусах Фаренгейта, а не в градусах Цельсия.
Вот немного более сложный пример:
TYPE POINT POSSREP POINT { X LENGTH, Y LENGTH } ;
VAR L LEHGTH ;
VAR P POINT ;
L := THE_X ( P ) ;
THE_X ( P ) := L ;
В первом присваивании переменной L типа LEHGTH присваивается координата X точки, являющейся текущим значением переменной P типа POINT ; во втором – текущее значение переменной L типа LEHGTH используется для обновления координаты X переменной P типа POINT . Операции THE _ X и THE _ Y фактически раскрывают возможное представление точек посредством “Декартовых координат” как для целей обновления, так и для целей только чтения; и снова это возможное представление не обязательно совпадает с реальным представлением.
Заметим теперь, что псевдопеременные THE _ логически необязательны. Рассмотрим второе присваивание в первом примере. Это присваивание, в котором используется псевдопеременная, логически эквивалентно другому, в котором псевдопеременная не используется:
TEMP := CELSIUS ( CEL ) ; /* вызов селектора CELSIUS */
Вот логический эквивалент второго присваивания во втором примере без использования псевдопеременной:
P := POINT ( L, THE_Y ( P ) ) ; /* вызов селектора POINT */
Другими словами, псевдопеременные как таковые не являются строго необходимыми для поддержки обсуждаемой разновидности обновления на уровне компонентов. Однако подход с использованием псевдопеременных интуитивно выглядит более привлекательным, чем альтернативный (для которого первый подходможно рассматривать как сокращенную форму); более того, он также обеспечивает высокую степень устойчивости к изменениям синтаксиса соответствующего селектора.
Заметим также, что по поводу реализации операций раскрытия возможного представления можно сделать замечания, аналогичные тем, которые приводились выше в связи с операциями выбора значений скалярного типа.
В объектной технологии имеется одна
В объектной технологии имеется одна безусловно хорошая идея – определяемые пользователями типы (включая определяемые пользователями операции). Одна идея является вероятно хорошей – наследование типа (хотя не здесь судить, насколько именно хорошей ). Ключевой технической идеей Третьего Манифеста является то, что эти две идеи полностью ортогональны реляционной модели. Чтобы достичь желательной объектной функциональности, не надо абсолютно ничего делать с реляционной моделью.
Пользователям требуются истинно реляционные СУБД (“истинно реляционные системы” не означают SQL-ориентированные системы), в которых содержится должная поддержка доменов, и тогда они получат “объектно/реляционные” СУБД, которых добивались. Привлекательность собственно
объектных СУБД (в противоположность “объектно/реляционным” СУБД) можно целиком объяснить частичной неудачей существующих поставщиков SQL-ориентированных систем в части должной поддержки реляционной модели. Но это не является аргументом для отказа от реляционной модели.
это именованное множество скалярных значений.
Скалярный тип данных
– для краткости, скалярный тип – это именованное множество скалярных значений. Два скалярных типа одинаковы в том и только в том случае, когда на самом деле являются одним и тем же типом (что подразумевает, в частности, наличие у них одного и того же имени; если типы не одинаковы, их имена должны различаться). Язык D должен обеспечивать пользователям возможности определять собственные скалярные типы (определяемые пользователями скалярные типы); другие скалярные типы должны обеспечиваться системой (встроенные или определяемые системой скалярные типы). Должна иметься возможность уничтожения определенных пользователями скалярных типов. Значениями заданного скалярного типа и переменными, значения которых должны принадлежать данному скалярному типу, можно оперировать только с помощью операций, определенных для этого типа (говорится, что операция “определена для” данного типа T , или “ассоциирована с” ним, если и только если хотя бы один ее параметр объявлен с указанием типа Т – см. RM -предписание 3). Для каждого скалярного типа и каждого объявленного возможного представления его значений (см. RM -предписание 4) в состав этих операций должны входить:
Операция selector, служащая для выборки произвольного значения данного скалярного типа (см. RM-предписание 4);
Набор операций для раскрытия рассматриваемого возможного представления (см. RM-предписание 5).
В состав определяемых системой скалярных типов должен входить тип truth value (с ровно двумя значениями, true и false). Для этого типа должны прямо или косвенно определяться и поддерживаться все четыре унарные и 16 бинарных логических операций.99
Все скалярные значения должны быть типизированы, т.е., по крайней мере, концептуально должны позволять идентифицировать (уникальный) тип, которому они принадлежат.
Скалярная операция
- это операция, которая возвращает скалярное значение или обновляет скалярную переменную. Язык D должен обеспечивать для пользователей возможности определения собственных скалярных операций (определяемых пользователями скалярных операций); другие такие операции (встроенные или определяемые системой скалярные операции) должны обеспечиваться системой. В общем случае должно быть возможно уничтожать определенные пользователями скалярные операции (хотя операции, требуемые RM-предписаниями 5, 8 и 21, слегка нарушают это предписание в том отношении, что их можно уничтожить только посредствам уничтожения ассоциированного типа, и то же верно для операций выборки). Кроме того:
Определение скалярной операции должно включать спецификацию типа каждого параметра этой операции, объявленный тип параметра. Если операция Op
имеет параметр P объявленного типа T, то аргумент A, соответствующий P, в каждом вызове Op должен иметь тот же тип T.
Каждая скалярная операция представляет из себя либо операцию обновления, либо операцию только чтения. Скалярная операция обновления – это такая скалярная операция, по меньшей мере один аргумент которой должен быть задан путем указания скалярной переменной, а не произвольного скалярного выражения, и вызов операции приводит к присваиванию значений таким аргументам (по крайней мере, потенциально); параметры, соответствующие подобным аргументам, называются подлежащими обновлению. Скалярная операция только чтения – это скалярная операция, не являющаяся скалярной операцией обновления.
Вызов скалярной операции только чтения должен возвращать (скалярный) результат. Вызов скалярной операции обновления – нет.
В определении скалярной операции только чтения должна содержаться спецификация типа результата этой операции, объявленного типа этого результата (в просторечии, объявление типа собственно операции).
В определение скалярной операции обновления должно указываться, какие аргументы являются подлежащими изменению.
Пусть T – скалярный тип, а v – вид ( в некотором контексте) некоторого значения этого типа. Тогда по определению у v имеется в точности одно реальное представление и одно или более возможных представлений (по крайней мере, одно, так как, очевидно, одно возможное представление всегда существует и совпадает с реальным представлением). Реальные представления, связанные с типом T, должны определяться средствами некоторого языка определения структуры хранения и не должны быть видимы в языке D (см. RM-предписание 6). По крайней мере одно возможное представление (не обязательно совпадающее с реальным представлением), связанное с типом T, должно быть объявлено как часть определения T
и, следовательно, должно быть видимо в языке D. Для каждого объявленного возможного представления PR типа T должна автоматически обеспечиваться операция selector S со следующими свойствами:
Для определенности предположим, что компоненты PR (см. RM-предписание 5) и параметры S представлены в виде упорядоченных списков. Тогда эти два списка должны содержать одно и то же число элементов, скажем n, и объявленные типы i-тых элементов списков (i = 1, 2, ..., n) должны быть одинаковы.
Каждое значение типа T
должно производиться путем некоторого вызова S.
Каждый (успешный) вызов S должен производить некоторое значение типа T. 101
Пусть некоторое объявленное возможное представление PR для скалярного типа T определено в терминах компонентов C1, C2, ..., Cn (у каждого компонента имеются имя и объявленный тип). Пусть v
– значение типа T, а PR(v) обозначает соответствующее возможное представление. Тогда PR(v)
должно быть раскрываемым – иначе говоря, должен автоматически обеспечиваться набор операций только чтения и обновления, такой что:
Для всех таких значений v и для всех i (i
= 1, 2, ..., n) можно “выбрать” (т.е. прочитать значение) компонента Ci из PR(v).
Для любой переменной V объявленного типа T и для всех i (i
= 1, 2, ..., n) можно обновить V таким образом, что если значениями V до и после обновления являются v и v’
соответственно, то возможные представления PR(v) и PR(v’) отличаются самое большее в их компонентах Ci.
Такой набор операций должен обеспечиваться для каждого возможного представления, объявленного в определении T.
Должен поддерживаться генератор типов TUPLE .102 То есть при наличии некоторого заголовка кортежа H (см. RM-предписание 9) должна быть возможность использовать генерируемый тип TUPLE {H} как основу определения (или, в случае значений, выборки):
значений и переменных этого генерируемого типа (см. RM-предписания 9 и 12);
значений атрибутов кортежей и атрибутов заголовка кортежей этого генерируемого типа (снова см. RM-предписание 9);
компонентов объявленных возможных представлений этого генерируемого типа (RM-предписание 5).
Генерируемый тип TUPLE {H} называется типом кортежей; имя этого типа – TUPLE {H}. Терминология степени, атрибутов и заголовков, вводимая в RM-предписании 9, должна применяться, с необходимыми изменениями,к этому типу кортежей, а также к значениям и переменным этого типа (см. RM -предписание 12). Типы кортежей TUPLE {H1} и TUPLE {H2} одинаковы в том и только в том случае, когда H1 = H2. В состав применимых операций должны входить аналоги операций реляционной алгебры RENAME, project, EXTEND и JOIN (см. RM-предписание 18), а также операции присваивания кортежей (см. RM-предписание 21) и сравнения кортежей (RM-предписание 22); кроме того, в состав операций должны входить (a) операция выборки кортежей (RM-предписание 9), (b) операция извлечения из указанного кортежа значения указанного атрибута (степень этого кортежа должна равняться единице – см. RM-предписание 9) и (c) операции “вкладывания” и “выкладывания” кортежей.
Должен поддерживаться генератор типов RELATION. То есть при наличии некоторого заголовка отношения H
(см. RM-предписание 10) должна иметься возможность использования генерируемого типа RELATION {H} как основы для определения (или, в случае значений, для выборки):
значений и переменных этого генерируемого типа (RM-предписания 10 и 13);
значений атрибутов кортежей и атрибутов заголовка кортежей этого генерируемого типа (см. RM-предписание 9);
компонентов объявленных возможных представлений этого генерируемого типа (RM-предписание 5).
Генерируемый тип RELATION {H} называется типом отношения, и имя этого типа – RELATION {H}. Терминология степени, атрибутов и заголовков, вводимая в RM-предписании 10, должна применяться, с необходимыми изменениями,к этому типу отношения, а также к значениям и переменным этого типа (см. RM -предписание 13). Типы отношения RELATION {H1} и RELATION {H2} одинаковы в том и только в том случае, когда H1 = H2. В состав применимых операций должны входить операции реляционной алгебры (см. RM-предписание 18), а также операции реляционного присваивания (см. RM-предписание 21) и реляционного сравнения (RM-предписание 22); кроме того, в состав операций должны входить (a) операция выборки отношений (RM-предписание 10), (b) операция извлечения единственного кортежа из указанного отношения мощности один (RM-предписание 10), и (c) операции “вкладывания” и “выкладывания” отношений.
Комментарии
С точки зрения любого отношения, которое включает атрибут, определенный на таком домене, “скалярные” значения в этом домене (как и значения всех доменов) являются все еще инкапсулированными. (Аналогичное замечание относится также к RM -предписанию 6.) В Третьем манифесте не поддерживаются в явном виде отношения в форме NF 2 (“NF в квадрате”103), введение которых влечет существенные расширения классической реляционной алгебры.
Для каждого типа должна поддерживаться операция сравнения по равенству, “=”. Пусть выражения X1 и X2
имеют значения v1 и v2 соответственно, причем v 1 и v 2 принадлежат одному и тому же типу T . Тогда операция X1 = X2 вырабатывает значение true в том и только в том случае, если v1 и v2 в действительности являются одним и тем же элементом T (то есть тогда и только тогда, когда X1 и X2 имеют одно и то же значение). Кроме того, пусть Op – это операция с параметром P объявленного типа T. Тогда для всех таких операций Op, если значением сравнения X1 = X2 является true , последствия двух (успешных) вызовов Op, которые отличаются только тем, что в одном из них аргументом, соответствующим P, является X1, а в другом – X2, должны быть неразличимы. Или, по-другому, если существует такая операция Op, что последствия двух (успешных) вызовов Op, которые отличаются только тем, что в одном из них аргументом, соответствующим P, является X1, а в другом – X2, различимы, то значением сравнения X1 = X2 должно быть false.
Значение кортежа t (или для краткости кортеж) – это множество упорядоченных триплетов вида <A, T, v>, где:
A – имя атрибута кортежа t. Никакие два различных триплета в t не должны содержать одно и то же имя атрибута;
T – имя типа атрибута A кортежа t.
v – значение типа T, называемое значением атрибута A кортежа t.
Мощность множества триплетов в t, или число атрибутов t называется степенью t. Множество упорядоченных пар <A, T>, получающихся путем удаления компонента v (значения) из каждого триплета, является заголовком t. Кортеж t называется соответствующим
этому заголовку (принадлежит к соответствующему типу кортежа – см. RM-предписание 6). Степенью
заголовка является степень кортежа, а атрибутами и соответствующими типами заголовка являются атрибуты и соответствующие типы кортежа t. При заданном заголовке H должна быть доступна операция selector для выборки произвольного кортежа, соответствующего H.
Значение отношения
r (для краткости – отношение) состоит из заголовка и тела, где:
Заголовком r является заголовок кортежа H как определяется в RM-предписании 9. Отношение r называется соответствующим этому заголовку (принадлежит к соответствующему типу отношения – см. RM-предписание 7), а степенью r является степень этого заголовка. Атрибутами и соответствующими типами r являются атрибуты и соответствующие типы H.
Тело r – это множество B кортежей, каждый из которых имеет заголовок H; мощность тела называется мощностью
r.
При заданном заголовке отношения H должна быть доступна операция selector для выборки произвольного отношения, соответствующего H.
Комментарии
Каждый кортеж в R содержит в точности одно значениеv для каждого атрибута A в H . Иными словами, R находится в первой нормальной форме, 1NF .
Проводится строгое различие между отношениями как таковыми и переменными-отношениями (см. РМ-предписание13).104
Скалярная переменная типа T – это переменная, допустимыми значениями которой являются скаляры указанного скалярного типа T, объявленного типа этой переменной. Язык D
должен обеспечивать для пользователей возможности определения скалярных переменных. При определении скалярной переменной должна производиться инициализация переменной некоторым значениям – явно указанным в операции определения переменной или не указанным явно, а определенным в реализации.
Переменная кортежа типа TUPLE {H} – это переменная, допустимыми значениями которой являются кортежи, соответствующие указанному заголовку кортежа H. Объявленный тип этой переменной кортежа есть TUPLE {H}. Атрибутами переменной кортежа являются атрибуты H, соответствующими типами – объявленные типы этих атрибутов, степенью переменной кортежа является степень H. Язык D должны обеспечивать для пользователей возможности определения переменных кортежей. При определении переменной кортежа должна производиться инициализация переменной некоторым значением – явно указанным в операции определения переменной или не указанным явно, а определенным в реализации.
Переменная отношения (relation variable , для краткости – relvar) типа RELATION {H} – это переменная, допустимыми значениями которой являются отношения, соответствующие указанному заголовку отношения H. Объявленный тип relvar есть RELATION {H}. Атрибутами relvar являются атрибуты H, соответствующими типами – объявленные типы этих атрибутов, степенью relvar является степень H. Язык D должен обеспечивать для пользователей средства определения и уничтожения переменных relvar базы данных (для тех relvar, которые принадлежат базе данных, а не приложению – см. RM-предписание 16). Язык D должен также поддерживать возможности определения relvar на уровне приложений.
Переменные r elvar базы данных могут быть реальными или виртуальными. Виртуальная relvar – это relvar базы данных, значением которой в любой момент времени является результат вычисления некоторого реляционного выражения, указываемого при определении этой relvar. Реальная relvar – это relvar базы данных, которая не является виртуальной. При определении реальной relvar должна производиться ее инициализация пустым отношением (т.е. отношением мощности нуль).
Комментарии
Реальные и виртуальные relvar соответствуют тому, что обычно называют “базовыми отношениями” и “обновляемыми представлениями” соответственно. Однако Д&Д полагают, что обновляемые представления составляют значительно более широкую категорию представлений, чем это принято считать при использовании традиционных подходов.
По определению у каждой relvar имеется по меньшей мере один возможный ключ. По меньшей мере один такой ключ должен быть определен при определении relvar, и не должна иметься возможность ликвидировать все возможные ключи данной relvar (кроме как ликвидировав саму relvar).
База данных – это именованный контейнер relvar; содержимое базы данных в любой момент времени – это набор relvar базы данных. Операции, необходимые для определения и ликвидации баз данных, не должны являться частью языка D (другими словами, определение и ликвидация баз данных должна производиться “за пределами среды D”).
Каждая транзакция
должна взаимодействовать в точности с одной базой данных. Однако разные транзакции должны иметь возможность взаимодействия с разными базами данных, и разные базы данных не обязательно должны быть разъединенными. Кроме того, транзакции должны иметь возможность определять новые и уничтожать существующие relvar внутри соответствующей базы данных (RM-предписание 13).
В языке D должны поддерживаться обычные операции реляционной алгебры (или их некоторые логические эквиваленты). Конкретно, должны прямо или косвенно поддерживаться, по меньшей мере, операции RENAME, restrict (WHERE), project, EXTEND, JOIN, UNION, INTERSECT, MINUS, (обобщенная) DIVIDEBY PER и (обобщенная) SUMMIRIZE PER. Все такие операции должны выражаться без чрезмерного многословия. В языке D
должен также обязательно поддерживаться механизм вывода типов отношения, благодаря чему заголовок результата вычисления произвольного реляционного выражения должен быть правильно определенным и известным как системе, так и пользователю (RM-предписание 7).105
Комментарии
Оборот “без чрезмерного многословия” предполагает наряду с другими вещами, что:
Должны быть в равной мере легко выразимы кванторы всеобщности и существования. Например, если D включает специальную операцию для реляционной проекции отношения, то он должен также включать и специальный оператор для общей формы реляционного деления.
Должны быть также в равной мере легко выразимы проекция на указанные атрибуты и проекция на все атрибуты, кроме указанных.
Имена relvar и вызовы селектора отношений должны быть допустимыми реляционными выражениями. В реляционных выражениях должна допускаться рекурсия.106
В D должны поддерживаться возможности для определения и уничтожения операций только чтения со значениями-отношениями. Отношение, являющееся результатом вызова такой операции, должно определяться некоторым реляционным выражением, указываемым при определении операции. В этом выражении должно допускаться наличие параметров; наличие таких параметров должно допускаться в любом месте, где допускаются вызовы селекторов (операций выборки). Вызовы таких операций внутри реляционных выражений должны допускаться в любом месте, где разрешаются вызовы селекторов отношений.
В D должно допускаться:
присваивание
(значения) скалярного выражения скалярной переменной;
присваивание
(значения) кортежного выражения переменной кортежа;
присваивание
(значения) реляционного выражения relvar.
В каждом случае типы источника и цели должны совпадать. В дополнение к этому в языке D должна поддерживаться множественная форма операции присваивания, в которой несколько отдельных операций присваивания выполняются параллельно как одна логическая операции.
В D должны поддерживаться некоторые операции сравнения, а именно:
Операции сравнения скаляров должны включать “=”, “¹ ” и, возможно, “<”, “>” и т.д. (в зависимости от данного скалярного типа);
Операции сравнения кортежей должны включать “=” и “¹ ” (и только);
Операции сравнения отношений должны включать “=”, “¹ ”, “Í ”, “является подмножеством” и т.д.;
Должна поддерживаться операция “Î ” для проверки вхождения кортежа в отношение.
Во всех случаях, кроме “Î ”, операнды должны быть одного типа, а в случае “Î ” кортеж и отношение должны иметь одинаковые заголовки.
Выражение, при вычислении которого вырабатывается истинностное значение, называется логическим выражением (также называемое истинностным, условным или булевским выражением). Ограничением целостности является логическое выражение, которое: a) именовано; b) является замкнутой WFF (Well Formed Formula – правильно построенной формулой) реляционного исчисления или ее логическим эквивалентом; с) при вычислении должно вырабатывать значение true. Язык D должен обеспечивать возможности для определения и уничтожения ограничений целостности. Такие ограничения должны классифицироваться на ограничения типа, атрибута, relvar и базы данных, и в D
должен поддерживаться механизм вывода
ограничений, ассоциированный с этой схемой классификации (насколько это осуществимо).
Для каждой relvar имеется соответствующий предикат relvar, и для каждой базы данных имеется соответствующий предикат базы данных. Все такие предикаты должны удовлетворяться в границах оператора.107
Комментарии
Предикат отношения представляет собой, по существу, конъюнкцию всех ограничений целостности, которые налагаются на соответствующую relvar , а предикат базы данных – это конъюнкция всех ограничений целостности, которые налагаются на соответствующую dbvar . Это исключительно важный момент – предикаты, а не имена представляют семантику базы данных.
Утверждение о том, что предикаты отношений должны удовлетворяться на границах операторов, означает в точности то, что никакая реляционная операция присваивания не должна оставлять какую-либо relvar в состоянии, в котором нарушается ее предикат отношения.
Из этого предписания, кроме того, следует, что должно быть невозможно обновлять “обновляемые представления” (т.е. виртуальные relvar ) таким образом, чтобы нарушалось определение этого представления. Иными словами, “обновляемые представления” всегда должны быть предметов того, что называется в SQL CASCADED CHECK OPTION [23].
Каждая база данных должна включать набор relvar, составляющих каталог этой базы данных. Должна существовать возможность производить присваивания для relvar каталога.
Комментарии
Из этого предписания следует, что каталог должен представлять собой нечто, что обычно называется “самоописанием”.
атрибуты которого различаются своими порядковыми
D не должен включать концепцию “отношения”, атрибуты которого различаются своими порядковыми позициями. Для каждого отношения r, выражаемого средствами D, атрибуты r должны различаться своими именами.
Комментарии
Из этого запрета следует, что не допускаются никакие анонимные столбцы, такие как в операторе SQL SELECT X + Y FROM T , и никакие дубликаты имен столбцов, как в операторах SQL SELECT X , X FROM T и SELECT T 1.X , T 2.X FROM T 1, T 2.
D не должен включать концепцию “отношения”, в котором кортежи различаются своими порядковыми позициями. Для каждого отношения r, выражаемого средствами D, кортежи r должны различаться своими значениями.
Комментарии
Из этого запрета вовсе не следует, что такое упорядочение не может быть введено, например, для целей представления. Скорее, из него следует, что в результате введения такого упорядочения отношение конвертируется в нечто, что не является отношением (возможно, в последовательность или упорядоченный список).
D не должен включать концепцию “отношения”, содержащего два различных кортежа t1 и t2
таких, что результатом сравнения кортежей “t 1 = t 2” является true . Отсюда следует, что (как уже утверждалось в RM -запрете 2) кортежи r должны различаться своими значениями.
Комментарии
Другими словами, “строки-дубликаты” являются незаконными абсолютно, категорически и однозначно незаконными.
D не должен включать концепцию отношения, в котором некоторый “кортеж” включает некоторый “атрибут”, не имеющий значения (соответствующего типа).
Комментарии
Другими словами – никаких неопределенных значений и никакой многозначной логики!
В D должно учитываться, что отношения без атрибутов приемлемы и интересны, и что то же относится к возможным ключам без компонентов.
D не должен содержать конструкции, которые связаны с “физическим” уровнем системы, уровнем “хранения”, “внутренним” уровнем или образованы под логическим влиянием этих уровней.
В D не должны поддерживаться покортежные операции над relvar или отношениями.
Комментарии
Операции INSERT , UPDATE и DELETE , если они обеспечиваются, вставляют, модифицируют или удаляют соответственно всегда множество кортежей. Множество, состоящее из одного кортежа, является всего лишь частным случаем.
Покортежная выборка (аналогичная той, которая выполняется через курсор посредством SQL -оператора FETCH ) – хотя она запрещается и вообще считается бесполезной – фактически может выполняться, если это желательно, путем конвертирования этого отношения в упорядоченный список кортежей и итерирования этого списка.
Категорически запрещается покортежное обновление (аналогичное операторам SQL UPDATE и DELETE , выполняемым через курсор).
D не должен включать какую-либо специальную поддержку “составных”, или “сложных” атрибутов, поскольку подобной функциональности можно достичь, если это желательно, более понятным образом на основе уже предписанной поддержки типов.
D не должен включать операции, “отвергающие ограничения доменов”, поскольку такие операции являются нештатными и необязательными.
RM-запреты
Внимательный читатель заметит, что многие из запретов в этом разделе являются логическими следствиями RM -предписаний. Однако в связи с теми ошибками, которые были, к сожалению, допущены в SQL , Д&Д ощущают, что в целях пояснения необходимо описать некоторые из этих следствий.
Система типов
Здесь мы кратко обсудим основные положения [20], связанные с построением системы типов, собрав воедино развернутые комментарии Д&Д к разным предписаниям, запретам и очень строгие суждения Третьего манифеста.
Скалярные типы
Термин тип
охватывает и скалярные и не скалярные типы. Между скалярными и не скалярными типами имеется принципиальное различие. Скалярные типы вне зависимости от уровня сложности их реальных представлений – не содержат компонентов, видимых для пользователя.115 Напротив, не скалярные типы содержат видимые для пользователя компоненты; в частности, типы кортежей и отношений не являются скалярными и содержат наборы видимых для пользователя атрибутов.
Значения некоторого скалярного типа обобщенно называются скалярными значениями (для краткости, скалярами). Аналогично, переменные, значения которых ограничиваются скалярами, обобщенно называются скалярными переменными. Реальное представление таких значений и переменных может быть сколь угодно сложным.
Скалярные типы могут определяться пользователями либо быть системно-определенными (“встроенными”). Требуется, чтобы поддерживался хотя бы один встроенный скалярный тип – тип истинностного значения. Для определенности предполагается, что для этого типа поддерживаются операции NOT , AND и OR и литералы TRUE и FALSE . Для удобства считается, что поддерживаются также встроенные скалярные типы INTEGER , RATIONAL (Д&Д предпочитают использовать этот термин вместо REAL ) и CHAR с соответствующими операциями и литералами.
Вот несколько примеров определений пользовательских скалярных типов (используется синтаксис Tutorial D , который в данном случае не требует пояснений).
TYPE S# POSSREP { CHAR } ;
TYPE QTY POSSREP { INTEGER CONSTRAINT QTY > 0 } ;
Здесь у типа S # имеется только одно объявленное возможное представление (“POSSREP ”), обладающее именем S # по умолчанию.116У этого возможного представления имеется ровно один компонент, имя которого по умолчанию совпадает с именем возможного представления, т.е. опять S # . Поскольку этот компонент определяется как принадлежащий типу CHAR , и не указано какое-либо дополнительное ограничение для типа S # , множество допустимых значений этого типа является множеством всех значений, которые можно представить в виде символьных строк.
Тип QTY определяется аналогичным образом, но для него указано дополнительное ограничение – значения этого типа должны быть положительными.
Вот несколько более сложных примеров определения скалярных типов:
TYPE LENGHT POSSREP { L RATIONAL } ;
TYPE POINT
POSSREP POINT { X LENGHT, Y LENGHT
CONSTRAINT … } ;
POSSREP POLAR { R LENGHT, THETA ANGLE
CONSTRAINT … } ;
TYPE POLYGON
POSSREP { VERTICES
RELATION { V# INTEGER, VERTEX POINT
CONSTRAINT … } ;
Определение типаLENGTH аналогично ранее приведенным определениям типов за исключением того, что единственному компоненту возможного представления этого типа задано явное имя L . ТипPOINT (“точка”) отличается от предыдущих примеров тем, что у него есть два различных объявленных возможных представления: первое –POINT (у этого возможного представления то же имя, что и у типа), с компонентами (Декартовыми координатами) X и Y , и второе – POLAR с компонентами (полярными координатами)R и THETA . Только в тех случаях, когда заданный тип имеет два или более объявленных возможных представлений, необходимо давать таким возможным представлениям явные имена. ТипELLIPSE (“эллипс”) отличается от предыдущих примеров тем, что его объявленное возможное представление основано не на встроенных, а на определенных пользователем типахLENGTH и POINT . Наконец, типPOLYGON (“многоугольник”) отличается от предыдущих примеров тем, что единственный компонент его объявленного возможного представления VERTICES принимает значения-отношения. То есть многоугольник представлялся бы отношением, содержащим по одному кортежу для каждой вершины этого многоугольника; этот кортеж содержал бы номер вершины (значение типаINTEGER ) вместе с самой соответствующей вершиной (значение типа POINT ).
Следует подчеркнуть, что операция определения типа реально не создает соответствующего множества значений. Концептуально, это множество значений уже существует и всегда будет существовать.
Все, что делает операция “определения типа”, заключается в введении имени, посредством которого можно ссылаться на это множество значений. Из RM -предписания 2 следует, что любое значение всегда относится к одному и только одному типу (если не поддерживается наследование). Побочным (но важным) следствием является то, что пересечение множеств значений любых двух различных типов всегда пусто (опять же при отсутствии наследования).
Скалярная операция – это операция, возвращающая скалярное значение или обновляющая скалярную переменную. 117 Как и скалярные типы, скалярные операции могут определяться либо пользователями, либо системой (“встраиваться”). Встроенные операции определяются только в связи со встроенными типами. Предполагается, что для встроенных скалярных типов BOOLEAN , INTEGER , RATIONAL и CHAR поддерживается естественный для этих типов набор операций, причем имена некоторых операций перегружены. Определяемые пользователями операции можно определять как для встроенных типов, так и для определяемых пользователями.
Факт существования операции с заданным именем не препятствует возможности перегрузки – то есть определения другой операции с тем же именем, но с другими объявленными типами параметров и (возможно) результатов, и следовательно, по крайней мере, частично отличной семантикой. Можно было бы даже не только перегрузить, но и переопределить существующую операцию посредством определения другой операции с тем же именем и теми же объявленными типами параметров и результатов, но с другой семантикой. По очевидным соображениям, мы рекомендуем, чтобы это средство использовалось со всеми возможными предосторожностями.
Вот пример определяемой пользователем скалярной операции, работающей со встроенным типом:
OPERATOR ABS ( N RATIONAL ) RETURNS RATIONAL ;
RETURN CASE
WHEN N ³ 0.0 THEN +N
WHEN N < 0.0 THEN –N
END CASE ;
END OPERATOR ;
Операция ABS определяется с единственным параметром N объявленного типа RATIONAL и возвращает результат того же объявленного типа.
Это операция только чтения, что означает, что ни при каком вызове функция не пытается обновлять свой собственный аргумент.
Вот другой пример определяемой пользователем скалярной операции только чтения, которая работает с некоторыми определяемыми пользователем типами:
OPERATOR DIST ( P1 POINT, P2 POINT ) RETURNS LENGTH ;
RETURN WITH THE_X ( P1 ) AS X1 ,
THE_X ( P2 ) AS X2 ,
THE_Y ( P1 ) AS Y1 ,
THE_Y ( P2 ) AS Y2 ,
SORT ( ( X1 - X2 ) ** 2 + ( Y1 - Y2 ) ** 2 ) ) ;
END OPERATOR ;
Эта операция, DIST (“расстояние”) определяется с двумя параметров P 1 и P 2 объявленного типа POINT , и возвращает результат объявленного типа LENGTH . Операции THE _ X и THE _ Y используются для получения координат X и Y двух рассматриваемых точек, затем эти координаты используются для получения требуемого расстояния. WITH позволяет ввести сокращения для некоторых выражений.
Для определенности принимается, что аргументы вызовов операций задаются в позиционной нотации, т.е. в данном вызове i -й аргумент в списке аргументов соответствует i -му параметру в списке параметров определения операции.
Вот пример операции обновления:
OPERATOR REFLECT ( P POINT ) UPDATES P ;
BEGIN ;
THE_X ( P ) := THE_X ( P ) ;
THE_Y ( P ) := THE_Y ( P ) ;
RETURN ;
END OPERATOR ;
Операция REFLECT фактически перемещает точку с декартовыми координатами (x ,y ) в центрально-симметричную точку (- x ,- y ). Операция определяется с одним параметром P объявленного типа POINT и при вызове должным образом обновляет аргумент, соответствующий этому параметру. Как в предыдущем примере, операции THE _ X и THE _ Y используются для “чтения” координат X и Y заданной точки; псевдопеременныеTHE _ X и THE _ Y используются для обновления этих координат. Вызов REFLECT не возвращает результата; такой вызов не имеет значения и не является скалярным выражением. Поэтому вызов должен выполняться посредством явного оператора CALL (или некоторого его логического эквивалента).
Типы данных и объектные классы
Чтобы иметь возможность детально обсуждать соотношение между объектной и реляционной технологиями, необходимо разобраться в том, какая концепция в реляционном мире является двойником концепции объектного класса в объектном мире.114
Этот вопрос исключительно важен, поскольку объектный класс является фундаментальной концепцией объектного мира, и все остальные объектные понятия в большей или меньшей степени зависят от этой концепции. В качестве ответа на поставленный выше вопрос возможны два ответа: (a ) концепции объектного класса соответствует концепция домена; (b ) концепции объектного класса соответствует концепция отношения (вернее, переменной отношения, relvar ). Д&Д доказывают, что верен только первый ответ. При этом в качестве аксиомы принимается то, что требуется оставаться в классической реляционной среде.
Для начала требуется навести должный порядок в реляционной терминологии. Как следует из классических определений реляционной модели данных, каждое отношение состоит из двух частей, заголовка и тела, где заголовок – это множество пар имя-столбца:имя-домена,
Предлагается следующий способ понимания природы отношений: Для заданного отношения R
заголовок R обозначает некоторый предикат (истинностную функцию), а каждая строка тела R – это некоторое истинное высказывание, получаемое из предиката путем подстановки некоторых значений доменов вместо заменителей или параметров этого предиката (“инстанциация предиката”). Для примера рассмотрим отношение MMQ (“ведомость материалов”) (рис. 3.1).
MAJOR_P# : P# | MINOR_P# : P# | QTY : QTY |
P1 | P2 | 5 |
P1 | P2 | 3 |
P2 | P3 | 2 |
P2 | P4 | 7 |
P3 | P5 | 4 |
P 4 | P 6 | 8 |
Рис. 3.1. Пример отношения ведомости материалов MMQ (в заголовке показаны имена атрибутов и доменов)
Заголовку отношения MMQ соответствует “деталь MAJOR _ P # содержит QTY деталей MINOR _ P # ”. Следующие высказывания являются истинными: “деталь P 1 содержит 5 деталей P 2 ” (получено подстановкой значений доменов P 1 , 5 и P 2 ); “деталь P 1 содержит 3 детали P 3” (получено подстановкой доменных значений P1 , 3 и P3 ) и т.д.
Другими словами, домены состоят из вещей, о которых мы говорим; отношения состоят из истин, которые мы изрекаем по поводу этих вещей.
Из этого следует, что ( a ) необходимы и домены, и отношения (без доменов не о чем говорить, без отношений нельзя ничего сказать); ( b ) домены и отношения – это не одно и то же; домены и отношения достаточны, равно как и необходимы; с логической точки зрения больше ничего не требуется.
Когда люди говорят об отношениях, они очень часто имеют в виду переменные отношений, а не сами
отношения. В действительности это частный случай логического различия между значениями и переменными. Например, значение данного отношения (множество строк) не меняется во времени, а значение переменной этого отношения меняется. Замечая, что подобно отношению и в отличие от переменной отношения значение данного домена (множество скаляров) также не меняется во времени, можно придти к ложному заключению, что домены и отношения являются вещами одного и того же вида. И наконец, смешение понятий собственно отношений и переменных отношений, приводит к тому (еще большему) заблуждению, что домены и переменные отношений – это одно и то же. Для достижения предельной ясности Д&Д вводят явный термин relvar
как сокращенную форму от relation variable (переменная отношения) и высказываются в терминах relvars, а не отношений, когда имеются в виду действительно переменные отношения.
Теперь можно обсудить то соотношение понятий, которое Д&Д считают правильным – концепция домена соответствует концепции объектного класса. Обычно считается, что домен – это всего лишь концептуальный пул значений, из которого берутся реальные значения столбцов отношений. Такое понимание является удовлетворительным только до поры до времени. В действительности, домен – это то же самое, что тип данных – определенный в системе или определенный пользователем тип. Поэтому эти термины являются взаимозаменяемыми. С понятием типа данных ассоциируется понятие операций, которые допускается применять к значениям этого типа (со значениями типа можно работать только посредством применения операций, определенных для этого типа).
Различаются собственно тип (или домен) и внутреннее представление,или физическая кодировка значений этого типа внутри системы. Например, номера деталей могли бы быть представлены внутренним образом как строки символов, но отсюда не следует, что можно производить операции с номерами деталей как со строками символов. Операции, определяемые для данного типа, зависят от предполагаемого смысла или семантики этого типа, а не от способа представления значений типа в системе. Внутренние представления значений типа должны быть скрыты от пользователя. Подобная строгая типизация в понимании Д&Д означает, что (a) у каждого значения имеется тип и (b) при попытке выполнения любой операции система проверяет, что операнды имеют типы, допустимые для этой операции.
В реляционной модели нет ничего, для чего требовалось бы ограничить типы данных только простыми формами. Единственным требованием является то, что значениями домена можно манипулировать только посредством определенных для него операций; внутреннее представление должно быть скрыто. Другими словами, вопрос о том, какие поддерживаются типы данных, ортогонален вопросу поддержки реляционной модели.
Итак, в реляционном мире домен – это тип данных, определяемый системой или пользователем, значениями которого можно манипулировать только с помощью определенных для него операций (и внутреннее представление которого может быть произвольно сложным, но скрытым от пользователя). Если обратиться к объектному миру, выясняется, что самое фундаментальное среди всех понятий, объектный класс, это тип данных, определенный системой или пользователем, значениями которого можно манипулировать исключительно посредством операторов, определенных для этого типа (и внутреннее представление которого может быть сколь угодно сложным, но скрытым от пользователя). Другими словами, домены и объектные классы – это одно и то же; это обеспечивает ключ к интеграции двух технологий, и именно эта позиция отстаивается в Третьем Манифесте.
Уравнивание объектного класса с relvar является серьезной логической ошибкой.По мнению Д&Д истоки этой ошибки кроятся в синтаксической близости определений класса и переменной отношения. Принципиальное различие понятий заключается в том, что relvar – это переменная, а класс – это тип. (Переменная отношения и домен - это не одно и то же.) Это уже показывает ошибочность уравнивания объектного класса с relvar . Более подробный анализ позволяет придти к выводу, что принятие второго вида уравнивания понятий подрывает концептуальную целостность реляционной модели.
Типы кортежей и отношений
Кортежные типы и типы отношений являются генерируемыми типами, получаемыми путем применения генераторов типа TUPLE и RELATION соответственно. Вот пример использования кортежного типа:
VAR ADDR TUPLE { STREET CHAR,
CITY CHAR,
STATE CHAR,
ZIP CHAR } ;
Здесь определяется кортежная переменная ADDR типа
TUPLE { STREET CHAR, CITY CHAR, STATE CHAR, ZIP CHAR }
Это пример генерируемого (кортежного) типа. Каждая из комбинаций “имя : тип” является атрибутом этого кортежного типа, и множество всех таких атрибутов является заголовком кортежного типа. Мощность этого множества называется степенью кортежного типа. Кортежная переменная ADDR имеет те же самые атрибуты, заголовок и степень, и то же касается всех возможных значений этой переменной.
Умышленно не поддерживается отдельная операция “определения типа кортежа”. Одним из оснований для такого решения является то, что иначе потребовалось бы вводить имя кортежного типа (помимо уже существующего имени TUPLE {…}). Такие дополнительные имена усложнили бы другие аспекты предлагаемого Д&Д подхода, например, решения вопроса о том, когда два типа совпадают.119
По этим соображениям предписывается, чтобы кортежные типыиспользовались “в виде подстановки”, как часть операции, которая определяет кортежную переменную отдельно.
Для кортежных типов требуется поддержка “операций, аналогичных операциям RENAME , project , EXTEND и JOIN из реляционной алгебры”. Вот несколько примеров, не требующих специальных пояснений (в последнем примере присутствует вызов селектора кортежей
– фактически, кортежный литерал):
ADDR RENAME ZIP AS POSTCODE /* переименование атрибута кортежа */
ADDR RENAME PREFIX ' ST ' AS ' G ' /* то же самое, префиксный вариант */
ADDR { STATE , ZIP } /* проекция кортежа */
EXTEND ADDR ADD NAME ('Clark Kent') AS NAME /* расширение кортежа */
ADDR JOIN /* соединение кортежей */
TUPPLE { NAME NAME ('Clark Kent') , COUNTRY 'USA' }
Вот пример присваивания кортежей:
ADDR := TUPLE {STREET 'One Jacob Way' ,
CITY 'Reading' ,
STATE 'Massachusetts' ,
ZIP '01870' } ;
Выражение справа от знака присваивания является другим примером вызова селектора кортежей (конечно, это всего лишь кортежный литерал). Переменная кортежа, указанная в левой части кортежного присваивания, и кортеж, обозначенный кортежным выражением в правой части, должны быть одного и того же кортежного типа, т.е. они должны иметь совпадающие имена атрибутов, и соответствующие атрибуты должны быть в свою очередь одного и того же типа.
Следующий пример иллюстрирует обязательную операцию экстракции атрибута, которая выделяет значение указанного атрибута из указанного кортежа:
VAR STATE_VAR CHAR ;
STATE_VAR := STATE FROM ADDR ;
Явно допускается, чтобы кортежи (и отношения) включали атрибуты, значениями которых были бы кортежи. Операции, которые применяются к этим кортежным значениям, это в точности те же операции языка D , которые применяются к кортежным значениям вообще. Вотпример:
VAR NADDR1 TUPLE { NAME NAME,
ADDR TUPLE { STREET CHAR,
CITY CHAR,
STATE CHAR,
ZIP CHAR } } ;
Важное преимущество схемы именования типов кортежей, предписанной в Манифесте, состоит в том, что она облегчает задачу вывода типа результата произвольного кортежного выражения. Например, рассмотрим следующее кортежное выражение (проекцию кортежа):
NADDR2 { NAME, ZIP }
Это конкретное выражение вычисляет кортеж, который порождается из текущего значения NADDR2 путем “проецирования на все, кроме” атрибутовSTREET , CITY и STATE . И кортежный тип этого порожденного кортежа есть в точности
TUPLE { NAME NAME, ZIP CHAR }
Рассмотрим следующие кортежные типы:
TUPLE { NAME NAME, ADDR TUPLE { STREET CHAR, CITY CHAR,
STATE CHAR, ZIP CHAR } }
TUPLE { NAME NAME, STREET CHAR, CITY CHAR,
STATE CHAR, ZIP CHAR }
Будем называть эти два типа TT 1 и TT 2 соответственно. Пусть теперь NADDR 1 и NADDR 2 являются переменными кортежа типов TT 1 и TT 2 , соответственно. Тогда:
Выражение
NADDR2 WRAP { STREET, CITY, STATE, ZIP } AS ADDR
принимает текущее значение NADDR 2 и “обволакивает” компоненты STREET , CITY , STATE и ZIP этого значения, производя единственный компонент ADDR с кортежным значением. Результат выражения принадлежит, таким образом, типу TT 1 , и тогда (например) допустимо такое присвоение:
NADDR1 := NADDR2 WRAP { STREET, CITY, STATE, ZIP } AS ADDR ;
Выражение
NADDR1 UNWRAP ADDR
принимает текущее значение NADDR1 и “разворачивает” компонент ADDR (с кортежным значением) этого значения, производя четыре скалярных компонента STREET , CITY , STATE и ZIP . Результат выражения принадлежит, таким образом, типу TT 2 , и тогда допустимо (например) такое присваивание:
NADDR2 := NADDR1 UNWRAP ADDR ;
Все, что говорилось выше по поводу кортежных типов, с небольшими коррективами применимо к типам отношений, и мы не будем повторяться. Остановимся только на двух дополнительных операциях – GROUP и UNGROUP . Рассмотрим следующие типы отношения:
RELATION { S# S#, PQ RELATION { P# P#, QTY QTY } … }
RELATION { S# S#, P# P#, QTY QTY }
Назовем эти два типа отношения RT 1 и RT 2 соответственно. Пусть теперь SPQ 1 и SPQ 2 – это relvar типов RT 1 и RT 2 соответственно. Тогда:
Выражение s
SPQ2 GROUP { P#, QTY } AS PQ
(которое можно было бы прочитать как “сгруппировать SPQ 2 по S # ”, гдеS # –единственный атрибут SPQ 2 , не упомянутый в спецификации GROUP ) вырабатывает отношение, определяемое следующим образом. Во-первых, заголовок выглядит следующим образом:
{ S # S #, PQ RELATION { P # P #, QTY QTY } }
Во-вторых, тело включает ровно по одному кортежу для каждого уникального значения S # в SPQ 2 (и не содержит никаких других кортежей). Каждый кортеж этого тела состоит из соответствующего значения S # (скажем, s ) и значения PQ (скажем, pq ), получаемого следующим образом:
Во-первых, каждый кортеж SPQ 2 заменяется на кортеж (скажем, x ), в котором компоненты P # и QTY обернуты в компонент (скажем, y ) с кортежными значениями.
Компоненты y всех таких кортежей x , у которых значение S # равно s , “группируются” в отношение pq , и тем самым генерируется результирующий кортеж со значением S #, равным s , и значением PQ , равным pq
Таким образом, общий результат относится к типу RT1, и поэтому (например) допустимо следующее присваивание:
SPQ1 := SPQ2 GROUP { P#, QTY } AS PQ ;
Выражение
SPQ 1 UNGROUP PQ
производит отношение, определяемое следующим образом. Во-первых, заголовок выглядит следующим образом:
{ S# S#, P# P#, QTY QTY }
Во-вторых, тело содержит в точности по одному кортежу для каждой комбинации кортежа в SPQ 1 и кортежа в значенииPQ внутри этого кортежа SPQ 1 (и не содержит никаких других кортежей). Каждый кортеж в этом теле состоит из соответствующего значения S # (скажем, s ) и значений P # и QTY (скажем, p и q ), получаемых следующим образом:
Во-первых, каждый кортеж SPQ 1 заменяется на множество кортежей, по одному такому кортежу (скажем, x ) для каждого кортежа в значении PQ кортежа SPQ 1 . Каждый такой кортеж x содержит компонент S # , равный компоненту S # из соответствующего кортежа SPQ 1 , и компонент с кортежным значением (скажем, y ), равный некоторому кортежу из компонента PQ того же кортежа SPQ 1 .
Компоненты y каждого кортежа x , в котором значение S # равняется s , разворачиваются в отдельные компоненты P # и QTY (скажем, p и q ), и тем самым генерируется результирующий кортеж со значением S # , равным s , значением P # , равным p , и значением QTY , равным q .
Таким образом, окончательный результат относится к типу RT 2, и поэтому допустимо следующее присваивание:
SPQ2 := SPQ1 UNGROUP PQ ;
Третий манифест
Статья [3] представляет собой манифест, касающийся будущего систем управления данными и СУБД. Д&Д следуют традициям первых двух манифестов [1 – 2] и надеются, что данный манифест сможет их заменить. Это обосновывает выбор названия. В [1] презрительно отвергается реляционная модель данных, игнорируется ее важность и значимость. Вместе с этим, как считают Д&Д, эта работа терпит неудачу в попытке определить какую-либо четкую линию. В [2] вежливо отдается должное реляционной модели, но в погоне за идеалами этой модели не упоминается и не подчеркивается безнадежность продолжения следования извращению этой модели, воплощенному в SQL . В отличие от этого, Д&Д твердо убеждены, что любая попытка двигаться вперед, чтобы выдержать испытание временем, должна сопровождаться полным и недвусмысленным отказом от SQL . При этом должно уделяться некоторое внимание вопросу, что следует делать с наследством SQL .
Основы будущих систем баз данных не способен обеспечить язык SQL . Д&Д полагают, что любые такие основы должны корениться в реляционной модели данных, впервые представленной миру Э.Ф. Коддом в 1969 г. [4]
Д&Д в полной мере осознают желательность поддержки некоторых активно обсуждавшихся возможностей, в частности, тех возможностей, которые считаются присущими объектной ориентации. Однако они полагают, что эти возможности ортогональны реляционной модели. И поэтому реляционная модель не нуждается в каком-либо расширении, в какой-либо коррекции, и самое главное, в каких-либо извращениях, чтобы можно было связать эти возможности с некоторым языком баз данных, способным представлять искомые основы. Предположим, что такой язык существует и называется D”.96
В Третьем манифесте язык D является предметом формулируемых предписаний и запретов.97
Некоторые предписания проистекают из существа реляционной модели, и Д&Д называют их RM -предписаниями. Предписания, не связанные с реляционной моделью, называются OO -предписаниями (от Other Orthogonal ). Аналогичным образом разделяются запреты.
RM -предписания и RM -запреты абсолютны и не могут быть предметом компромисса. К сожалению, этого нельзя сказать про OO -предписания и OO -запреты, поскольку ко времени написания статьи не существовало общепринятой модели, на которой они могли бы базироваться.98
Д&Д полагают, что OO -предписания могут внести значительный вклад в областях определяемых пользователями типов данных и наследования. Д&Д предпринимают усилия, чтобы привести в этих областях собственные определения, и предупреждают читателя, что наследование порождает ряд вопросов, на которые в доступной литературе отсутствуют ответы. Поэтому в этой области предписания необходимо могут быть только предварительными. Наряду с предписаниями и запретами, Третий манифест включает некоторые весьма строгие суждения, которые также подразделяются на RM - и OO -категории.
Третий манифест: назад к реляционному будущему
В марте 1995 г. была впервые официально опубликована статья Хью Дарвена и Кристофера Дейта, названная авторами “Третьим манифестом” [3]. Прежде, чем перейти к сути Третьего манифеста, немного поговорим про его авторов.
Крис Дейт начал свою карьеру в компании IBM , где, естественно, специализировался в области технологии баз данных. С конца 70-х годов активно занимается писательской деятельности. В 1983 г. Крис Дейт покинул IBM и с тех пор является независимым консультантом. Основным трудом К. Дейта является учебная монография “Введение в системы баз данных”. В 2003 г. вышло в свет уже восьмое издание этой книги. Каждое издание книги существенно отличается предыдущих изданий, но не снижает их собственную значимость. На русском языке опубликованы три издания “Введения в системы баз данных” – 2- e издание [24], 6-е издание [25] и 7-е издание [26]. Дейт также написал и издал серию книг, посвященным конкретным системам: DB 2 [14], SQL / DS и Sybase . В 1997 г. была издана книга [23], написанная при участии Хью Дарвена и являющаяся одним из лучших руководств по стандарту SQL :1992. К. Дейт пишет много статей, которые печатались, главным образом, в журнале Database Programming and Design . Когда этот журнал прекратил свое существование, Дейт некоторое время публиковался в журнале Intelligent Enterprise , в последние годы публикует свои статьи на сайте Фабиана Паскаля (см. [15]). Подборки статей Дейта, а теперь еще и Дарвена издаются в сборниках серии Selected Writings [16]. С 1995 г. К. Дейт (вместе с Хью Дарвеном) развивает и пропагандирует идеи Третьего манифеста.
Хью Дарвен всю жизнь (с 1967 г.) работает в отделении компании IBM в Великобритании. Одной из его профессиональных обязанностей является участие в комитете по стандартизации языка SQL . Дарвен начал сотрудничать с Дейтом в конце 80-х, участвуя в подборе статей для сборников избранных статей. Хью Дарвен принимал участие в написании руководства по стандарту SQL :1992 [23]. Полноправным соавтором Дейта Дарвен стал в 1998 г., когда вышло первое издание книги, посвященной Третьему манифесту.
Итак, в 1998 году вышло первое издание книги Дейта в соавторстве с Хью Дарвеном “Foundation for Object/Relational Databases: The Third Manifesto” [19]. Комментированный пересказ первых двух глав этой книги опубликован в журнале “Открытые системы” [17]. В 2000 году было выпущено второе издание книги под названием “ Foundation for Future Database Systems: The Third Manifesto ” [20]. Это издание подготовлено к публикации на русском языке [21], но к моменту написания этих строк еще не вышло в свет. В 2002 г. появилась еще одна новая книга Дейта и Дарвена (к компании которых присоединился Никос Лоренцос) [18]. В этой книге идеи Третьего манифеста применяются к технологии темпоральных баз данных.
Чтобы плавно подойти к предпосылкам и истокам Третьего манифеста, проследим эволюцию взглядов Криса Дейта.92 Вспомним, что Дейт начинал свою производственную деятельность в компании IBM именно в то время, когда активно развивалась теория реляционных баз данных, и предпринимались первые попытки реализации реляционных СУБД. С одной стороны, Дейт воспитывался на чисто реляционных идеях Эдгарда Кодда [3.2], а с другой стороны участвовал в создании коммерческой СУБД SQL / DS , где эти идеи (как он впоследствии осознал) уже начинали искажаться.
В своих первых книгах, например, в [14] и [24], Крис Дейт еще вполне лояльно относился к коммерческим реляционным СУБД и языку SQL . Но уже в 1984 г. он написал и издал статью “Критика языка баз данных SQL ” [22], в которой обсуждались недостатки используемого в то время варианта языка. В шестом издании своей основной книги [25] (1995 г.) Дейт очень резко говорит об SQL (имея в виду стандарт SQL :1992), а в книге [22] грамотное и лаконичное описание стандарта языка соседствует с очень язвительными (хотя и весьма остроумными) замечаниями. Заметим, что замечания Дейта по поводу недостатков языка SQL всегда носили очень конструктивный характер – он стремился не только показать отклонения SQL от принципов реляционной модели данных, но и продемонстрировать, что желаемую функциональность можно было получить без потребности в этих отклонениях.
В этой ситуации публикации Первого и Второго манифестов [1 – 2]не могли быть спокойно восприняты Дейтом. Действительно, в Первом манифесте по существупредлагалосьреволюционным образом отказаться от “устаревшей” реляционной модели данных и перейти к применению парадигмы объектной ориентированности в области управления данными. Естественно, это противоречило убеждению Дейта о совершенстве и универсальности реляционной модели. Во Втором манифесте лукаво говорилось о необходимости сохранения поддержки реляционной модели в системах баз данных следующего поколения, но в действительности речь шла о поддержке SQL . Естественно, это противоречило убеждению Дейта об ущербности и ограниченности языка SQL .
Конечно, можно было выбрать привычный для Дейта способ реакции – опубликовать серию статей с критикой обоих манифестов. Но это было бы не конструктивно, поскольку не предлагался бы какой-либо “правильный” (с точки зрения Дейта) путь дальнейшего развития технологии баз данных. Так родился Третий манифест, представляющий собой набор достаточно точно сформулированных конструктивных предложений, следование которым может (по мнению Дейта) привести к созданию СУБД следующего поколения, удовлетворяющим современным потребностям и базирующимся на чистой реляционной модели93.
В документе [3] почти совсем отсутствует критика предыдущих манифестов (и чего бы то ни было другого). Зато критика с избытком представлена в книгах [18 – 19]. Обсудим, по какой причине Хью Дарвену и Крису Дейту94 понадобилось писать специальную книгу, посвященную Третьему манифесту. Все дело в том, что положение Д&Д коренным образом отличается от положения авторов первых двух манифестов. Эти авторы сочиняли свои манифесты, опираясь на существующие коммерческие (или хотя бы исследовательские) реализации. Цель каждого из манифестов состояла в действительности в том, чтобы показать правильность направления, по которому движется соответствующая область индустрии систем управления данными. За спиной Д&Д не было ничего, кроме классической реляционной теории.
Поэтому, чтобы Третий манифест не выглядел голословным, необходимо было произвести его детальную проработку.
Естественно, два человека (талантливых и очень образованных человека), ни один из которых не имеет практического опыта проектирования и разработки СУБД, никак не могут довести свои идеи не только до стадии реализации, но даже до стадии технического проектирования. Поэтому в [18 – 19] Д&Д постоянно подчеркивают, что их обсуждения находятся на модельном, а не на реализационном уровне. Более того, Д&Д выражают желание, чтобы их книга рассматривалась бы как современное изложение реляционной модели данных. Однако, по мнению автора данной статьи, во многих местах [18 – 19] материал носит существенно более конкретный характер, чем это принято при описании абстрактных моделей.
Мы начнем этот раздел с изложения Третьего манифеста в том виде, в котором он приведен в [19].95
Во втором разделе мы кратко обсудим наиболее интересные идеи [19], относящиеся к системе типов и модели наследования. Кроме того, мы приведем критику Д&Д и собственные комментарии по поводу первых двух манифестов и связанных с ними работ. Наконец, в третьем разделе будет рассмотрена первая попытка создания коммерческой СУБД, основанной на идеях Третьего манифеста.
[] [] []
document.write('
|
<
This Web server launched on February 24, 1997 Copyright © 1997-2000 CIT, © 2001-2009 |
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. |
Качественная в короткие сроки. |