Języki i Środowiska Programowania Baz Danych | |||||||||||
|
2. Rozszerzenie SBQL w modelu M2 Jak dotąd, tylko podejście stosowe umożliwia definicję języka zapytań dla modelu obiektowości zakładającego dynamiczne role obiektów (określanego przez nas jako model M2). Pozostałe podejścia do języków zapytań, jak dotąd, nie rozważają (nie zauważyły) takiej koncepcji. Można jednak z góry twierdzić, że opanowanie pełnej semantyki tego modelu na gruncie algebry, logiki lub jakiegoś wyspecjalizowanego rachunku będzie nieuchronnie prowadzić do ograniczeń koncepcji i zasadniczych trudności pojęciowo-formalnych. Zmiana w stosunku do modeli M0 i M1 polega na sposobie zapełniania bazowych sekcji stosu. Mianowicie, w tym przypadku sekcja bazowa musi zawierać bindery do wszystkich ról obiektów. Jest to zgodne z interpretacją modelu M2 przedstawionego na Rys.30 i Rys.31, gdzie identyfikatory startowe (zbiór) R obejmują wszystkie aktualne role wszystkich obiektów. Zwrócimy uwagę, że w naszym modelu M2 obiekt występuje wyłącznie jako konglomerat ról, z jedną wyróżnioną rolą główną. Dla tego przykładu dolne sekcje stosu ENVS są przedstawione na Rys.62.
Dla przykładu modelu M2 przestawionego na Rys.31 pokażemy, w jaki sposób zarządza się stosem środowiskowym dla operatora niealgebraicznego where, Rys.63. Podobnie stos będzie się zachowywać dla innych operatorów niealgebraicznych. Rozważmy zapytanie:
gdzie n jest dowolną nazwą występującą wewnątrz podzapytania po where; n nie jest objęta innym operatorem niealgebraicznym. Zakładamy, że aktualnie operator where przetwarza rolę Prac posiadającą identyfikator i16. Przykładowo, dla zapytania
nazwa Wiek będzie związana w czwartej sekcji stosu, licząc od góry. Uogólnimy sytuację przedstawioną na Rys.63. Załóżmy, że rola R1 dziedziczy dynamicznie z roli R2 która dziedziczy dynamicznie z roli R3 itd. Niech Ri (i=1,2,...) będzie członkiem klasy C1Ri która dziedziczy statycznie z klasy C2Ri, która dziedziczy statycznie z klasy C3Ri itd. Oznaczmy odpowiednie identyfikatory przez iR1, iR2, iR3, ..., iC1R1, iC2R1, iC3R1, ..., iC1R2, ... itd. Oczywiście, klasy CjRi (j = 1,2,...) nie muszą być unikalne; mogą tworzyć pewien graf dziedziczenia. Sytuacja ta jest przedstawiona na Rys.65. Rozważmy zapytanie q1 q q2, gdzie q jest pewnym operatorem niealgebraicznym, zaś q1 i q2 są podzapytaniami. Załóżmy, że q1 zwraca identyfikator roli R1. Wówczas q wkłada na wierzchołek stosu ENVS sekwencję sekcji przedstawioną na Rys.64. Może się zdarzyć, że pewne sekcje klas wkładanych na stos będą się powtarzać. Poza koncepcyjną redundancją (którą można łatwo wyeliminować w implementacji) w niczym to oczywiście nie przeszkadza, ponieważ istotna będzie tylko ta sekcja, która jest najbliższa wierzchołka stosu. Duplikaty tej sekcji znajdujące się poniżej tej sekcji nie będą uczestniczyć w wiązaniu nazw.
Po ewaluacji zapytania q2 wszystkie te sekcje będą zdjęte ze stosu. Reguły wiązania nazw są takie same, jak w przypadku modelu M0. Nie występują tu anomalie przy wiązaniu nazw, które były omawiane przy okazji modelu M1.
|
P10.9. | Podaj pracowników, którzy są jednocześnie studentami: |
Ewaluacja zapytania Student zwróci wszystkie identyfikatory wszystkich podról ról Osoba nazwanych Student. Operator rzutowania (Prac) zmieni niektóre
z nich na identyfikatory podról Prac (jeżeli obiekt ma jednocześnie role Student i Prac), zaś inne na wartość pustą.
P10.10. | Załóżmy, że role Student mają atrybut Stypendium. Dla każdej osoby należy zwrócić Nazwisko oraz dochody, które wynoszą 0, jeżeli dana osoba nie jest ani pracownikiem, ani studentem, Zar, jeżeli osoba jest pracownikiem, Stypendium, jeżeli osoba jest studentem lub Zar+Stypendium, jeżeli osoba jest jednocześnie pracownikiem i studentem. |
Pomocnicza nazwa p obiega wszystkie role Osoba. Po pierwszej kropce następuje wyliczenie wyniku dla pojedynczej wartości p. Na wynik ten składa się Nazwisko danej osoby oraz suma dochodów. Dla wyliczenie tej sumy tworzy się bag składając się z jednego, dwóch lub trzech elementów. Jeżeli p posiada rolę Student, to p jest rzutowane na tę rolę, a następnie z tej roli pobiera się Stypendium; podobnie dla roli Prac i atrybutu Zar.
Zwrócimy uwagę, że podane zapytanie w SBQL automatycznie uwzględni fakt, że dana osoba jest kilkakrotnie pracownikiem i/lub kilkakrotnie studentem. W takim przypadku operator rzutowania dla danego identyfikatora roli Osoba zwróci dwa lub więcej identyfikatorów ról Student lub Prac, ale oczywiście, w podanym zapytaniu nic to nie przeszkadza.
Innym udogodnieniem może być operator algebraiczny, który umożliwiłby przetestowanie, czy dana rola posiada podrolę o określonej nazwie. Niech taki operator ma postać
Rola has role nazwaRoli
gdzie zarówno nazwaRoli, jak i Rola są zapytaniami; nazwaRoli zwraca string będący nazwą testowanej roli, Rola zwraca identyfikator roli, np.:
P10.11. | Podaj, ile osób jest jednocześnie pracownikiem i studentem: |
Podane wyżej możliwości ułatwiają generyczne programowanie, ale nie rozwiązują kompleksowo tego problemu. Generalne rozwiązanie wymagałoby stworzenia metamodelu oraz repozytorium metadanych dla przechowywania wszelkich metainformacji związanych z definicjami klas, typów, interfejsów itd. w modelu M2 oraz powiązanie tego repozytorium z obiektami przechowywanymi w składzie. Propozycja takiego repozytorium jest zawarta w [Habe02a, Habe02b, Habe03b, Habe03a, Jodl03b, Subi03]. Takie repozytorium mogłoby być przeszukiwane za pomocą standardowego SBQL. Pełne możliwości programowania generycznego wymagałyby dodatkowo stworzenia mechanizmu refleksji [Roan02, Habe02a].
Niżej podsumujemy własności modelu z dynamicznymi rolami starając się podkreślić jego zalety i odmienność.