190
Integracja danych i aplikacji przy użyciu wirtualnych repozytoriów Michał Lentner Polsko-Japońska Wyższa Szkoła Technik Komputerowych Praca doktorska napisana pod kierunkiem prof. dr hab. inż. Kazimierza Subiety Polsko-Japońska Wyższa Szkoła Technik Komputerowych Warszawa, styczeń 2008

Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

  • Upload
    others

  • View
    10

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Integracja danych i aplikacji przy użyciu wirtualnych repozytoriów

Michał LentnerPolsko-Japońska Wyższa Szkoła Technik Komputerowych

Praca doktorska napisana pod kierunkiemprof. dr hab. inż. Kazimierza Subiety

Polsko-Japońska Wyższa Szkoła Technik Komputerowych

Warszawa, styczeń 2008

Page 2: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp
Page 3: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Streszczenie

Podstawowym celem rozprawy doktorskiej jest zbadanie nowych paradygmatów ułatwiających

proces implementacji systemów informatycznych. Przedstawiona w niej została propozycja

narzędzia programistycznego umożliwiającemu pracę programiście bazodanowemu na znacznie

wyższym poziomie, niż umożliwiają to popularne współczesne rozwiązania. W tym celu stworzony

został nowy, obiektowy język programowania, bezszwowo zintegrowany z konstrukcjami języka

zapytań (zapytania jako wyrażenia), razem z jego rozproszonym, bazodanowo zorientowanym

środowiskiem wykonawczym. Oprogramowanie to zapewnia funkcjonalność wielu istniejących

narzędzi (takich jak np. języki programowania aplikacji baz danych, języki zapytań do baz danych,

systemy zarządzania bazami danych, różnego rodzaju middleware) w jednym, spójnym,

uniwersalnym, łatwym do wykorzystania i efektywnym w użyciu środowisku programistycznym.

Praca została podzielona na siedem rozdziałów.

W pierwszym rozdziale przedstawiamy problem integracji danych i aplikacji jako jednego

z głównych czynników wpływającego na wydajność inżynierów wytwarzających oprogramowanie

biznesowe. Problem ten definiujemy z punktu widzenia dwóch aspektów: integracji języka

programowania z bazą danych, oraz integracji istniejących aplikacji w systemach rozproszonych.

Rozdział drugi poświęcony jest kilku najbardziej znanym obecnie podejściom do integracji danych

i aplikacji. Omawiamy tutaj zagadnienia związane z metodami łączenia aplikacji z relacyjnymi

i obiektowymi bazami danych, jak również najważniejsze rodzaje middleware.

3

Page 4: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

W rozdziale trzecim przedstawiamy skrótowo podejście stosowe do języków zapytań - teoretyczną

bazę na podstawie której zaprojektujemy prototypowy język programowania/zapytań zintegrowany

z obiektową bazą danych, funkcjonującą również jako middleware.

W rozdziale czwartych przedstawimy architekturę zaproponowanego przez nas narzędzia oraz

zaprezentujemy przykładowe scenariusze jego zastosowania w dziedzinie integracji danych

i aplikacji.

Kolejny rozdział, czyli rozdział piąty, jest nieformalnym opisem języka SBQL, rozszerzonego przez

nas na potrzeby niniejszej pracy do kompletnego języka programowania.

W związku z tym, iż język SBQL posiada szereg mechanizmów deklaratywnych, niezbędne jest

zaprojektowanie wydajnych algorytmów optymalizacyjnych dla zapytań. Podstawowe algorytmy

optymalizacyjne dla SBQL w środowisku scentralizowanym zostały już sformułowane, jednak

optymalizacja zapytań rozproszonych wymaga dodatkowych technik. Temu zagadnieniu

poświęcono zatem rozdział szósty.

Rozdział siódmy stanowi szczegółowa dyskusja na temat integracji danych za pomocą

aktualizowalnych perspektyw. Prezentujemy kod źródłowy prostego systemu trójwarstwowego

(klient-serwer integracyjny-serwery kontrybucyjne) oraz objaśniamy mechanizm wymiany danych

w takim środowisku.

Ostatni rozdział, czyli rozdział ósmy, dokumentuje szereg niskopoziomowych decyzji, jakie zostały

podjęte w celu zaimplementowania prototypu zaproponowanego przez nas narzędzia. Obok tekstu

niniejszej pracy, prototyp ten jest jednocześnie podstawowym rezultatem badań podjętych przez

autora rozprawy.

4

Page 5: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Integration of data and applications

using virtual repositories

Summary

The main objective of this Ph.D. thesis is to develop new software construction paradigms that

make the implementation of information systems easier. We have proposed an application

development environment allowing a database programmer to work on a much higher level of

abstraction than it is possible when current solutions are used. To this end, we have created a new

object-oriented programming language, seamlessly integrated with query language constructs

(queries as expressions) and with its distributed, database-oriented runtime environment. Our

software provides functionality of many existing tools (such as: database programming languages,

database query languages, database management systems, several kinds of middleware) in a single,

consistent, universal, easy to use and effective to apply programming environment.

The thesis is divided into seven chapters.

In the first chapter, a brief introduction to the problem of data and application integration is

discussed. The need for integration is presented as one of the most important factors influencing the

work of today’s business application developers. The problem is defined from the point of view of

two aspects: the integration of a programming language and a database management system, as well

as the integration of existing applications being parts of distributed systems.

5

Page 6: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

The second chapter is focused on highlighting some of the most popular approaches of data and

application integration. We have discussed several issues associated with existing methods of

connecting applications with relational and object-oriented databases, as well as the most important

types of middleware.

In the third chapter the Stack-Based Approach to query languages is briefly described.

It is presented as a theoretical base allowing us to construct a prototype programming/query

language integrated with an object-oriented database having middleware features.

In the fourth chapter the architecture of our prototype solution is introduced. Several typical

scenarios of its application in the area of data and application integration is also presented.

The fifth chapter contains an informal description of the SBQL language, extended by us to a fully-

fledged database programming language.

Since SBQL contains declarative constructs, it was necessary to design efficient query optimization

algorithms. The most important optimizations for SBQL queries executed in a centralized

environment have already been designed in other works. However, distributed query processing

requires completely new solutions. This issue has been discussed in the sixth chapter.

The seventh chapter contains a detailed discussion on data integration with the use of updateable

views. The source code of a simple, three-tier (client, integration server, contributory server) system

is presented. We have also explain the functionality of several low-level mechanisms responsible

for data exchange between particular nodes of the system.

The last chapter documents several low-level decisions which have been made in order to

implement a prototype of the tool discussed in this thesis. Apart from the text of the disseration,

the prototype is the main product of the research conducted by the Author.

6

Page 7: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Spis treści

.........................................................................................................Rozdział 1: Wprowadzenie 9

.......................................Rozdział 2: Stan sztuki w dziedzinie integracji danych i aplikacji 25

............................................................Rozdział 3: Podejście stosowe do języków zapytań 43

.................................Rozdział 4: Koncepcja architektury narzędzia RAD nowej generacji 59

.............................................................................Rozdział 5: Język SBQL w systemie Odra 71

..............................................................Rozdział 6: Optymalizacja zapytań rozproszonych 87

.....................................................................Rozdział 7: Integracja danych rozproszonych 107

...............................................................................................................Rozdział 8: Prototyp 119

............................................................................................................Podsumowanie pracy 143

.............................................................................Dodatek A: Przykładowy program SBQL 145

....................Dodatek B: Kod źródłowy zintegrowanego systemu połączeń kolejowych 149

....................................................Dodatek C: Ewaluacja przykładowego zapytania SBQL 155

................................................Dodatek D: Przetwarzanie danych XML za pomocą SBQL 157

..............................................Dodatek E: Ważniejsze operacje maszyny wirtualnej SBQL 165

................................................................Lista ważniejszych akronimów użytych w pracy 179

................................................................................................................................Literatura 183

Page 8: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp
Page 9: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdział 1:Wprowadzenie

Eksplozja informacjiW ostatnich latach obserwowana jest gwałtowna eksplozja ilości informacji, z jaką mają do

czynienia systemy informatyczne współczesnych organizacji. Zbadano, iż w ciągu trzech

poprzednich lat wygenerowano więcej informacji, niż zapisano w ciągu całej historii ludzkości [1].

Niestety, za tą eksplozją informacji oraz rozwojem potrzeb nie nadąża rozwój narzędzi

informatycznych. Nie dziwi więc, iż systemy wielu organizacji często załamują się pod wpływem

wielkiej ilości i różnorodności danych, jakie muszą być przetwarzane przez poszczególne (często

odizolowane od siebie) składniki tych systemów. Okazuje się, że wraz z rozwojem potrzeb

integracyjnych problem przetwarzania danych masowych w rozproszonych i heterogenicznych

środowiskach zdobywa coraz większe znaczenie, a narzędzia wspomagające czynności z tym

związane stają się coraz potrzebniejsze [2]. Nieprzerwanie rosnąca złożoność tych narzędzi wiąże

się jednak z tym, iż programiści coraz rzadziej zdolni są opanować wszystkie czynności, jakie

wynikają z produkcji oprogramowania w takich środowiskach. Ilość technologii, interfejsów

programistycznych, języków, bibliotek, protokołów, serwerów, etc., które współczesny programista

musi znać i używać jest wprost gigantyczna. Ten ciągle rosnący zakres technologii jest jedną

z przyczyn ogromnej zlożoności współczesnego oprogramowania, a co za tym idzie - kosztów jego

wytwarzania oraz pielęgnacji. Ponieważ w przyszłości problem ten będzie narastał, nieodzowne są

prace nad nowymi, prostymi w obsłudze, uniwersalnymi i homogenicznymi narzędziami

9

Page 10: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

programistycznymi wspomagającymi tworzenie aplikacji baz danych w środowiskach

rozproszonych.

ObiektowośćWalka ze złożonością oprogramowania wymaga przede wszystkim sięgnięcia do źródeł tej

złożoności, czyli sposobu postrzegania problemów przez człowieka oraz implementacji tych

problemów za pomocą maszyny. Okazuje się, iż im mniejsze są różnice, tym prostsze jest tworzenie

systemów informatycznych oraz tym mniejszy jest koszt ich wytworzenia i pielęgnacji.

Praktyka pokazała, iż jednym z najbardziej zaawansowanych obecnie paradygmatów

umożliwiających niwelowanie tych różnic jest obiektowość. Na przestrzeni lat okazało się, iż

pojęcia takie jak obiekt, klasa, asocjacja, metoda, specjalizacja, generalizacja, polimorfizm itp.,

bliższe są ludzkiemu sposobowi postrzegania świata, a realizowana przy ich pomocy struktura

danych/oprogramowania staje się bardziej intuicyjna. Dziś normą jest obiektowa analiza

i projektowanie oprogramowania za pomocą obiektowych notacji graficznych, oraz implementacja

oprogramowania za pomocą obiektowych języków programowania [6].

Rozwój obiektowości nie jest jednak zakończony. Pomimo wiodącej roli tego podejścia w analizie

oraz projektowaniu systemów oraz w językach programowania, idee obiektowości nie zyskały

dotychczas szerokiego uznania na polu baz danych. Standard ODMG [12], czyli próba

ustandaryzowania obiektowego modelu danych, języka zapytań i interfejsu programistycznego do

obiektowych baz danych okazał się klęską. Zaprezentowane w nim idee okazały się w dużym

stopniu nieimplementowalne dla twórców systemów zarządzania bazami danych, oraz

nieakceptowalne dla programistów aplikacji. Również powstające niezależnie od tego standardu

systemy zarządzania obiektowymi bazami danych nie zyskały dotychczas szerszego uznania,

dobrze sprawdzając się jedynie w niszowych zastosowaniach. Mnogość tymczasowych rozwiązań

zapewniejących mechanizmy odwzorowania relacyjno-obiektowego (realizowanych często ad-hoc

przez środowiska przemysłowe) pokazuje jednak, jak ważne dla współczesnych programistów jest

operowanie na bazach danych chociażby bez konieczności tłumaczenia struktur relacyjnych na

struktury obiektowe i odwrotnie.

Zalety obiektowych baz danych w stosunku do baz relacyjnych akcentowane w ubiegłej dekadzie

nie straciły zatem nic ze swej aktualności [34, 36, 32]. Są to przede wszystkim:

• Znacznie bogatszy model danych.

10

Page 11: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• Brak niezgodności impedancji pomiędzy modelem danych obiektowego języka

programowania i bazy danych.

• Ortogonalna trwałość.

• Potencjalnie wyższa wydajność (zwłaszcza w zakresie przetwarzania asocjacji).

Praktyczna realizacja tych postulatów stała się niestety trudniejsza niż początkowo przypuszczano.

Niektórzy specjaliści uważają wręcz, że idea obiektowych baz danych okazała się niemożliwą do

spełnienia utopią. Do najczęściej wymienianych wad obiektowych baz danych należą:

• Zbyt mocne powiązanie aplikacji z operacjami wykonywanymi na bazie danych.

• Przypadkowość rozwiązań, brak ogólnie przyjętego standardu, takiego jak SQL [87].

• Brak lub utrudnione korzystanie z języka zapytań.

Wszystkie te wady powodują, iż potrzebne są dalsze badania w tej dziedzinie. Niezbędne staje się

opracowanie zupełnie nowych architektur obiektowych baz danych, dramatycznie innych od

obecnie stosowanych. W przeciwnym razie bazy danych tego typu na zawsze skazane będą na

zastosowania niszowe, jako rozszerzenia tradycyjnych języków programowania.

Środowiska programowania aplikacji baz danychBazy danych są krytycznym elementem każdej współczesnej aplikacji biznesowej. Programiści

korzystają z baz danych w celu zapewnienia trwałości danym masowym oraz uzyskania do nich

szybkiego i bezpiecznego dostępu. Ponieważ dane lokalne aplikacji oraz dane przechowywane

w bazie danych należą do dwóch różnych światów, częścią praktycznie każdej współczesnej

aplikacji jest warstwa odpowiedzialna za wymianę danych pomiędzy tymi światami. Implementacja

takiej warstwy osiąga często nawet kilkadziesiąt procent objętości całego systemu, jest

niejednokrotnie źródłem błędów i frustracji programistów. Nie dziwią więc ciągłe próby

podejmowane przez światy naukowy i akademicki, zmierzające do integracji języków

programowania z bazami danych.

W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp do obiektów

aplikacyjnych i obiektów bazy danych realizowany powinien być z użyciem dokładnie tych samych

konstrukcji językowych. W praktyce taka bezszwowa integracja języka programowania z bazą

danych nie została dotychczas osiągnięta w satysfakcjonujący sposób. Idea ta realizowana jest

obecnie zazwyczaj poprzez rozszerzenie tradycyjnego języka programowania (np. Java) w taki

sposób, by niektóre obiekty (np. będące instancjami specjalnej klasy) nie miały charakteru ulotnego

11

Page 12: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

(znikały po wyłączeniu komputera), ale trwały (zapisywane były automatycznie na dysku

komputera). Idea ta została pierwotnie zapoczątkowana przez tzw. języki z trwałością (np.

Persistent Modula 3 [24], PJama [23], etc.), a następnie rozwijana w ramach obiektowych baz

danych. Dzięki tym rozwiązaniom udało się przede wszystkim ujednolicić modele danych. Ten

sam obiektowy model danych znajduje się zatem zarówno po stronie bazy danych, jak i języka

programowania. Programista nie jest dzięki temu zmuszony do utrzymywania dwóch

równoważnych struktur danych (np. tabel i obiektów), ale w przezroczysty sposób operuje na

trwałych obiektach. Technika zapoczątkowana przez języki z trwałością stała się również inspiracją

dla technologii wywodzących się ze środowisk przemysłowych i reprezentowanych przez techniki

odwzorowania relacyjno-obiektowego. Rozwiązania takie jak Hibernate próbują połączyć zalety

ortogonalnej trwałości, oraz dobrze znanych systemów zarządzania relacyjnymi bazami danych.

Realizowane jest to poprzez wprowadzenie dodatkowej warstwy metadanych (tworzonych przez

programistę), odwzorowującej strukturę obiektową aplikacji na strukturę relacyjnej bazy danych.

Języki z trwałością oraz bazujące na nich rozwiązania nie spotkały się z większym uznaniem

z powodu wad, w szczególnością jednej która naszym zdaniem całkowicie je dyskwalifikuje. Wadą

tą jest brak języka zapytań lub też język zapytań w szczątkowej formie. Powstaje z związku z tym

pewien dysonans - operacje aktualizacyjne pozbawione są niezgodności impedancji, natomiast

operacje wyszukiwawcze realizowane są w tradycyjny sposób (poprzez zagnieżdżanie zapytań jako

literałów, proceduralne przetwarzanie za pomocą iteratorów [29], etc.). Brak możliwości wyjścia z

tej sytuacji skłania niektórych autorów do stwierdzenia, że języki zapytań w obiektowych bazach

danych nie mogą być poprawnie zdefiniowane, albo wręcz że nie są potrzebne. Zamiast tego

proponuje się wyrażanie operacji wyszukiwawczych w bazie danych za pomocą języka takiego jak

Java czy C#. Okazuje się tymczasem, że rozwiązania takie jak native queries są nie tylko

nieporównywalnie uboższe nawet w stosunku do standardowego SQL, ale również praktycznie

uniemożliwiają realizację technik optymalizacyjnych, bez których konstrukcje deklaratywne tracą

sens. Naszym zdaniem eliminacja języków zapytań z obiektowych baz danych jest skazaniem ich

na porażkę. To właśnie dzięki językowi SQL mógł mieć miejsce tak przytłaczający sukces

relacyjnych baz danych.

Język zapytań jest niezwykle istotnym składnikiem każdego liczącego się obecnie systemu

zarządządzania bazą danych. Podstawowym zadaniem języka zapytań jest podwyższenie

wydajności programistów poprzez dostarczenie do ich dyspozycji pojęciowych, makroskopowych

12

Page 13: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

operacji, pozwalających zapisać złożone operacje związane z przetwarzaniem danych w zwartej,

czytelnej i zrozumiałej formie. Powszechną stała się opinia, że jedno zdanie napisane w języku

zapytań może zastąpić kilka stron programu napisanego w języku programowania ogólnego

przeznaczenia. Ma to krytyczne znaczenie dla tempa wytwarzania oprogramowania, jego kosztu,

pielęgnacyjności i modyfikowalności. Następnym powodem jest dążenie do podwyższenia

niezawodności produktów programistycznych, czemu sprzyja zwartość zapisu programu,

konceptualizacja myślenia programisty i tzw. niezależność danych, przejawiająca się m.in.

w abstrahowaniu od ich fizycznej organizacji. Jeszcze jednym powodem jest otwarcie nowych

możliwości dla automatycznej optymalizacji programów. Operacje makroskopowe dają w tym

względzie znacznie większe możliwości niż języki niskiego poziomu. Ten fakt jest potwierdzony

przez szereg badań dowodzących, że dla złożonych zapytań automatyczny optymalizator daje

lepsze wyniki niż ręczna optymalizacja [4, 39].

Wydaje się że różnice między językami zapytań i tradycyjnymi językami programowania są na tyle

duże, iż ich integracja jest po prostu niewykonalna. Naszym zdaniem nie jest możliwe stworzenie

wersji języka takiego jak Java czy C#, która w czysty semantycznie sposób pozwalałaby połączyć

ze sobą konstrukcje języka proceduralnego i języka zapytań. Przyczyną tego stanu rzeczy jest to,

iż języki zapytań bazują na zupełnie innych założeniach semantycznych i optymalizacyjnych:

konstrukcje imperatywne vs. konstrukcje deklaratywne, optymalizacja podczas kompilacji vs.

optymalizacja podczas czasu wykonania, algorytmy i struktury danych vs. tabele (w przypadku

systemów relacyjnych) i indeksy, wątki vs. transakcje, null jako wskaźnik vs. null jako brak

danych, różnice w składni, systemach typów, sposobie enkapsulacji danych, itp. Różnice te znane

są powszechnie pod nazwą “niezgodność impedancji”.

Jedynym sposobem na rozcięcie tego węzła gordyjskiego jest wprowadzenie nowej klasy języków

programowania, w których wyrażenia byłyby tożsame z zapytaniami, a rezultatami wyrażeń mogły

być kolekcje. Wyrażenia takie mogłyby posiadać właściwości tradycyjnych języków

programowania (literały, nazwy, operatory), ale mogłyby również umożliwiać deklaratywne

przetwarzanie dużych kolekcji danych. Operatory takiego języka powinny dawać się swobodnie

łączyć z innymi konstrukcjami języka, wliczając w to konstrukcje imperatywne, instrukcje sterujące

oraz abstrakcje programistyczne. Język taki powinien służyć zarówno do programowania strony

serwera bazy danych, ale również strony klienckiej. Programy takiego języka powinny być

uruchamiane w środowisku posiadającym cechy współczesnych systemów zarządzania bazami

13

Page 14: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

danych (trwałość, indeksy, optymalizacja zapytań, bezpieczeństwo, transakcje, itd.), ale również

maszyn wirtualnych (wirtualny zbiór instrukcji, pamięć, I/O). Poprzez przeniesie poziomu

abstrakcji na znacznie wyższy poziom niż w obecnych językach programowania, języki takie

pozwoliłyby na znaczące skrócenie czasu programowania oraz zwiększenie jakości wytwarzanego

przy ich użyciu oprogramowania.

Integracja rozproszonych danych i aplikacjiWe współczesnych systemach informatycznych zauważyć można tendencję zwiększonego

zapotrzebowania na zapewnienie możliwości komunikacji pomiędzy programami komputerowymi,

czy wręcz całymi systemami informatycznymi tych samych (Enterprise Application Integration,

EAI), bądź całkowicie odrębnych (Business To Business, B2B) organizacji. Użytkownicy domagają

się natychmiastowego dostępu do wszystkich informacji jakie posiada dana organizacja, niezależnie

od systemu, w jakim informacja ta jest przechowywana. Zadaniem projektantów jest zatem

sprawienie, by poszczególne systemy mogły ze sobą współpracować, czyli połączenie tzw. wysp

automatyzacji (odizolowanych od siebie systemów realizujące ściśle określone zadania) w jeden

wirtualny system informatyczny.

Jak dotąd istnieje szereg kontrowersji co do tego, jak taki wirtualny system miałby wyglądać od

strony technicznej. Przykładowo, niektórzy specjaliści postulują rozszerzenie tradycyjnego języka

programowania o zestaw narzędzi (zwykle bibliotek i/lub generatorów kodu źródłowego)

umożliwiających do pewnego stopnia przezroczyste dla programisty wykorzystywanie

rozproszonych zasobów. Inni postulują oparcie integracji na tzw. usługach, komunikujących się ze

sobą za pomocą standardowych protokołów i języków opisu danych. Jeszcze inni są zwolennikami

integracji na poziomie procesów biznesowych, albo poprzez portale biznesowe. Istnieje także grupa

zwolenników integracji aplikacji na poziomie danych - poprzez replikację danych (np. w hurtowni

danych), albo federację baz danych. Cechą wspólną wszystkich tych rozwiązań jest dążenie do

tego, by każda informacja była dostępna natychmiast, niezależniej od tego gdzie i w jakiej postaci

jest ona w rzeczywistości przechowywana. Mechanizmy integracyjne muszą zatem działać w czasie

rzeczywistym, oraz być na tyle sprawne, aby były w stanie współpracować z różnorodnymi bazami

danych, serwerami aplikacji, systemami zarządzania treścią, hurtowniami danych, systemami

przepływu prac, językami programowania, protokołami wymiany danych itp.

14

Page 15: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

MiddlewarePodstawowym mechanizmem warunkującym sprawną komunikację w środowisku rozproszonym

jest tzw. wartstwa pośrednia (middleware) [10]. Jest to oprogramowanie znajdujące się pomiędzy

systemem operacyjnym oraz aplikacją po każdej stronie systemu rozproszonego. Istnieje wiele

rodzajów middleware: rozproszone obiekty, serwery aplikacji, monitory transakcyjne, serwery

integracyjne, brokery komunikatów i inne. Najważniejszym zadaniem middleware jest uczynienie

procesu wytwarzania oprogramowania prostszym, poprzez dostarczenie abstrakcji

programistycznych wspólnych dla każdej strony systemu rozproszonego, ukrycie heterogeniczności

oraz dystrybucji systemów komputerowych, jak również niskopoziomowych szczegółów

dotyczących komunikacji.

Warto przy tym zauważyć, że aspekt przezroczystości w komunikacji rozproszonej nie jest jedynie

domeną middleware. Tematyka ta jest również przedmiotem badań w dziedzinie rozproszonych/

federacyjnych baz danych [47, 48, 51]. Na przestrzeni lat specjaliści z tej dziedziny wypracowali

znacznie bardziej zaawansowane aspekty przezroczystości niż te, które charakteryzują współczesne

middleware. Do najważniejszych form przezroczystości zapewnianych przez federacyjne (zwane

również wirtualnymi) bazy danych należą: przezroczystość dostępu, położenia, współbieżności,

heterogeniczności, skalowania, fragmentacji, replikacji, optymalizacji, awarii, migracji, i inne. [89]

Tradycyjne rodzaje middleware nie wspierają większości z tych własności, ponieważ nie są one

nastawione na przetwarzanie kolekcji, ani danych trwałych za pomocą konstrukcji deklaratywnych.

Middleware posiada zwykle charakter proceduralny, czyli znacznie niższy poziom abstrakcji niż

języki zapytań. Konieczności przetwarzania kolekcji w systemie rozproszonym nie można jednak

uniknąć. Problemy z tym związane widać szczególnie na przykładzie technologii rozproszonych

obiektów. Przykładowo, w technologiach takich jak CORBA [25] podjęto próbę ukrycia różnic

w dostępie do danych zdalnych i lokalnych. Ta iluzja okazała się zgubna dla wielu projektów

programistycznych ze względów wydajnościowych. Źródłem problemów była pokusa operowania

na danych zdalnych za pomocą takich samych algorytmów, jakie byłyby użyte gdyby dane te

znajdowały się w pamięci operacyjnej lokalnego komputera. Niestety, okazuje się że ze względu na

naturę pracy w sieciach komputerowych (czas dostępu, awaryjność) algorytmy te nie mogą być

takie same.

Twórcy standardu CORBA podjęli próbę wprowadzenia dodatkowych usług (Query Service,

Persistence Service) mających usprawnić obsługę danych masowych za pomocą języka zapytań.

15

Page 16: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Próba ta nie zakończyła się satysfakcjonującymi rezultatami, głównie ze względu na problem

niezgodności impedancji pomiędzy językami zapytań i tradycyjnymi językami programowania.

Podobna sytuacja dotyczy popularnej technologii EJB (Enterprise Java Beans) [52] - tzw. ziarna

encyjne (Entity Beans) oraz działający na nich język zapytań EJB QL nie rozwiązują naszym

zdaniem problemu przetwarzania rozproszonych danych masowych. Pomijając nawet fakt małych

możliwości tych języków zapytań, są one wręcz bezużyteczne w sytuacji gdy potrzebna jest

aplikacja kombinująca dane z różnych źródeł danych. Ze względu na niskopoziomową (poprzez

API) pracę z middleware sytuacje takie wymagają gigantycznych nakładów programistycznych

związanych z optymalizacją kodu. Optymalizacja taka rzadko jest możliwa do zrealizowania

w idealny sposób poprzez człowieka, ponieważ niejednokrotnie realizacja tej samej operacji

dostępu do danych może mieć wiele (np. tysiące) możliwych sposobów implementacji (tzw. planów

wykonania). Automatyczna optymalizacja rozproszonych zapytań za pomocą technik znanych

z rozproszonych baz danych mogłaby rozwiązać ten problem, niestety współczesne rodzaje

middleware nie posiadają takiej możliwości. Panujące obecnie trendy polegają raczej na ucieczce

od tego złożonego problemu. Przykładowo, najnowsze rozwiązania, oparte na idei tzw. architektury

zorientowanej na usługi (Service Oriented Architecture, SOA) całkowicie ignorują problem

przetwarzania danych masowych. Ich zwolennicy przekonują, iż SOA operuje na poziomie usług,

czyli na znacznie wyższym, niż zwykłe dane (wysokopoziomowa integracja usług vs.

niskopoziomowa integracja danych). Automatycznie zakłada się zatem, że zdalna procedura

(usługa) zaprojektowana została w taki sposób, by obsłużyć wszystkie możliwe sytuacje biznesowe

związane ze zdalnym dostępem do zasobów. Naszym zdaniem jest to złudne założenie, które

prowadzi do odkrywania na nowo dobrze znanych mechanizmów (np. transakcje dla WebServices)

przetwarzania danych w środowisku rozproszonym.

Obiektowa baza danych jako middleware

We współczesnych systemach informatycznych bazy danych wykorzystywane są w projektach

integracyjnych najczęściej wówczas, gdy problem da się rozwiązać za pomocą replikacji, federacji

lub poprzez budowę hurtowni danych. Jeśli projekt integracyjny wymaga wykorzystania takich

pojęć jak logika aplikacji, wówczas wykorzystywane są inne strategie integracyjne, np. integracja

poprzez usługi. Zauważmy jednak że te ograniczenia baz danych wynikają z prostoty relacyjnego

modelu danych i nie dotyczą baz obiektowych. Obiektowe bazy danych potencjalnie posiadają

zarówno zalety relacyjnych baz danych, jak i języków programowania, dlatego każda znana

strategia integracyjna może być wyrażona w kontekście takiego systemu.

16

Page 17: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Obiektowe bazy danych w projektach integracyjnych posiadają szereg znaczących zalet. Znacznie

wyższy poziom abstrakcji, na którym pracuje potencjalny inżynier integracyjny korzystający

z obiektowej bazy danych pozwala często wyrazić w jednej linii kod, który przy użyciu np.

środków opartych na standardzie CORBA przyjąłby postać dużego programu. Ma to znaczenie nie

tylko dla produktywności programistów, łatwości i stabilności tworzonego przez nich

oprogramowania, ale również umożliwia automatyczną optymalizację operacji na rozproszonych

danych. Taka automatyczna optymalizacja nie jest możliwa jeśli dany komponent systemu (np.

usługa) zostanie zaprogramowany w ramach niskopoziomowego języka programowania.

Jeśli integrowane mają być dane pochodzące ze źródeł heterogenicznych i integracja ma zachodzić

w czasie rzeczywistym, wówczas konieczne jest zbudowanie federacyjnej bazy danych. Obiektowe

bazy danych znane są tymczasem ze znacznie bogatszego modelu danych, pozwalającego na

łatwiejsze wyspecyfikowanie kanonicznego modelu danych obowiązującego w federacji. Pozwala

to zintegrować istniejące, rozproszone i heterogeniczne zbiory danych do postaci jednego,

wirtualnego repozytorium wszystkich danych jakimi dysponuje organizacja. Nie zależy to od tego,

czy integrowane zasoby to relacyjne, albo obiektowe bazy danych, repozytoria XML, czy dane

multimedialne. Tak różnorodne modele danych stanowią problem dla relacyjnego modelu danych,

ale nie dla wielu istniejących modeli obiektowych. Zauważmy, że nawet jeśli jako kanoniczny

model danych wybrany zostanie stosunkowo uniwersalny model danych XML, taka decyzja nie

gwarantuje sukcesu w integracji danych. Najpoważniejszymi problemami są tutaj m.in.: sposób

opisu globalnych danych danych, język zapytań i jego optymalizacja, oraz aktualizacji danych

z poziomu globalnego użytkownika. Ze względu na brak globalnego identyfikatora obiektu

(obecnego np. w CORBA, ale nie istniejącego obecnie w innych niż obiektowe modelach danych),

nie jest możliwe stworzenie generalnej metody modyfikowania zintegrowanych danych. Z tego

powodu, choć większość obecnych federacyjnych baz danych bez problemu potrafi udostępniać

dane do odczytu, operacje modyfikujące stan poszczególnych baz danych nie są możliwe w ogóle,

albo tylko w niektórych przypadkach. Ponieważ interfejs do danych globalnych zwykle

w federacyjnych bazach danych definiowany jest jako perspektywa, problem ten można rozszerzyć

do dużo szerszego i znanego od wielu lat problemu aktualizacji perspektyw. Perspektywy znane

z systemów relacyjnych (traktowane jako zapamiętane zapytynia) umożliwiają tymczasem

aktualizację danych wirtualnych tylko w najprostszych przypadkach. Przykładowo, nie można

aktualizować danych uzyskanych poprzez złączenie (z kilkoma drobnymi wyjątkami), albo

wygenerowanych za pomocą operatorów agregujących. Przezroczystość wszystkich operacji

17

Page 18: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

realizowanych na perspektywach jest tymczasem szczególnie wymagana w federacyjnej bazie

danych, gdzie perspektywy mogą integrować dane z tysięcy źródeł danych.

Okazuje się, że rozwiązanie problemu aktualizacji perspektyw musi wiązać się z wprowadzeniem

dużo bardziej wyspecjalizowanej struktury pełniącej rolę perspektywy. Takie struktury

zaprojektowane zostały dla obiektowych baz danych, i tylko w ich kontekście ich moc może być

w pełni wykorzystana. Wiąże się to m.in. z koniecznością rozszerzenia identyfikatora obiektu do

postaci umożliwiającej opisywanie wirtualnych danych. Wraz z definiowanymi przez twórców

perspektyw generycznymi procedurami przeciążającymi podstawowe operacje na wirtualnych

obiektach, identyfikatorami posiadającymi informację na temat perspektywy, oraz zapytania za

pomocą którego obiekty wirtualne są generowane, perspektywy takie umożliwiają modyfikację

dowolnych danych wirtualnych.

Strategie integracyjneSpecjaliści z dziedziny EAI zgodni są w jednej kwestii - żadna istniejąca obecnie metoda integracji,

czy też technologia nie jest złotym środkiem na każdy problem integracyjny [3, 11, 102].

Przykładowo, dla pewnej organizacji, niezbędna może być integracja danych zawartych w jej

bazach danych. Organizacja ta wymaga nieograniczonego dostępu do wszystkich swoich

danych i nie jest w stanie przewidzieć wszystkich ścieżek dostępu teraz lub w przyszłości.

Ponieważ zgodnie np. z architekturą SOA dostęp do nowego zbioru danych wiąże się z budową

nowej usługi, oznacza to w takiej sytuacji każdorazową modyfikację systemu docelowego,

co z różnych powodów (np. koszt) może być nieakceptowalne. Federacyjna baza danych jest więc

tutaj najlepszym rozwiązaniem.

Podobny problem może jednak nie dotyczyć takiej organizacji, która może skoncentrować się na

integracji logiki aplikacji, a nie przetwarzaniu rozproszonych danych. Poszczególne operacje

możliwe do realizacji na zintegrowanych systemach należących do tej organizacji są dobrze znane,

a ich interfejsy mają charakter statyczny. Dla takiej organizacji tak niskopoziomowa integracja, jaką

jest integracja danych, może okazać się zbyt skomplikowana. Możliwe dla niej jest zatem

wydzielenie dobrze zdefiniowanej funkcjonalności każdego z integrowanych systemów i globalne

ich opublikowanie jako usługi. Stworzony w ten sposób zbiór usług może stać się następnie

podstawą do integracji procesów biznesowych zachodzących w ramach takiej organizacji. Taka

wysokopoziomowa (i pożądana z punktu widzenia biznesu) integracja nie może być z kolei

wykorzystana w przypadku pierwszej z wymienionych organizacji.

18

Page 19: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Zauważmy, iż obecnie obie opisane wyżej organizacje do osiągnięcia swoich celów musiałyby

używać różnego zestawu narzędzi. Pierwsza z nich prawdopodobnie wykorzystałaby jakąś

relacyjną bazę danych umożliwiającą budowę federacyjnych baz danych (np. DB2 z wbudowanym

modułem Garlic), a druga - rozproszonych obiektów, middleware zorientowanego na komunikaty,

albo WebServices.

Naszym zdaniem wszystkie te rozwiązania możliwe są do wyrażenia za pomocą obiektowej bazy

danych zintegrowanej z językiem zapytań rozszerzonym do kompletnego języka programowania.

Narzędzie takie wykorzystane jako middleware może wnieść zupełnie nową jakość do tematyki

integracji aplikacji. Możliwość wykorzystania tego samego narzędzia do zrealizowania różnych

strategii integracyjnych powinna zwiększyć produktywność programistów, ograniczyć koszty

wytwarzania oprogramowania, skrócić czas nauki oraz zredukować liczbę struktur, koncepcji

i mechanizmów niezbędnych do opanowania przez programistów. W tej pracy skoncentrujemy na

zaprojektowaniu architektury takiego narzędzia.

Cel pracy doktorskiejPodstawowym celem rozprawy doktorskiej jest zbadanie nowych paradygmatów ułatwiających

proces implementacji systemów informatycznych. Zaprojektowana zostanie nowa metodologia

tworzenia aplikacji baz danych, wraz z prototypowym narzędziem, umożliwiającym pracę

programiście bazodanowemu na znacznie wyższym poziomie, niż umożliwiają to współczesne

rozwiązania. W tym celu stworzony zostanie nowy, obiektowy język programowania, bezszwowo

zintegrowany z konstrukcjami języka zapytań (zapytania jako wyrażenia), razem z jego

rozproszonym, bazodanowo zorientowanym, obiektowym środowiskiem wykonawczym.

Technologia ta zapewniać będzie funkcjonalność wielu istniejących narzędzi (takich jak np. języki

programowania aplikacji baz danych, języki zapytań do baz danych, systemy zarządzania bazami

danych, różnego rodzaju middleware) w jednym, spójnym, uniwersalnym, łatwym do

wykorzystania i efektywnym w użyciu środowisku programistycznym. Będzie to jednocześnie

propozycja nowej architektury obiektowych baz danych, konkurencyjna wobec istniejących

architektur obiektowych i relacyjnych SZBD.

Najważniejszym zadaniem takiego środowiska programistycznego będzie integracja rozproszonych

zasobów rozumianych jako dane, dlatego zagadnienie to stanowić będzie najpoważniejszy fragment

rozprawy. Integracja danych zrealizowana zostanie za pomocą koncepcji znanej pod nazwą

wirtualnego repozytorium. Zgodnie z tą koncepcją, wszystkie składniki systemu informatycznego

19

Page 20: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

widziane będą jako jedna, wirtualna, rozproszona baza danych i usług, dostępna za pomocą języka

zapytań. Zapewnienie odpowiedniego stopnia przezroczystości (przezroczystość danych/usług,

współbieżności, heterogeniczności, skalowania, fragmentacji, replikacji, migracji, optymalizacji,

itp.) niezbędnego w wirtualnym repozytorium osiągalne będzie w satysfakcjonującym stopniu

jedynie wówczas, gdy programista aplikacyjny zwolniony zostanie z ich ręcznego

zaprogramowania za pomocą języka ogólnego przeznaczenia (jak to ma miejsce w typowych

rozwiązaniach). Zamiast tego, za ich realizację odpowiedzialny powinien być system zarządzania

bazą danych sterowany za pomocą bardzo wysokopoziomowych konstrukcji deklaratywnych. Aby

korzystać z wirtualnego repozytorium, programista nie będzie zatem zmuszony do posługiwania się

złożonym API udostępnianym przez obecne middleware. Zamiast tego, pozwolimy mu pracować na

znacznie wyższym poziomie abstrakcji, ukrywając złożoność procesów komunikacyjnych,

mechanizmów bezpieczeństwa, transakcyjności i optymalizacji. Najważniejszą zaletą naszego

wirtualnego repozytorium będzie możliwość aktualizacji danych z poziomu globalnego

użytkownika. Właściwość tę osiągniemy poprzez wykorzystanie w pełni aktualizowalnych

perspektyw, wykorzystywanych jako osłony/mediatory i nie mających precedensu w istniejących

rozwiązaniach z dziedziny integracji danych i aplikacji.

Zaproponowane przez nas narzędzie posiadało będzie potencjał zostania samodzielnym

środowiskiem programistycznym, dostarczającym możliwości budowy aplikacji baz danych oraz

samych baz danych. Integracja danych i aplikacji zbudowanych za pomocą wyłącznie tego

środowiska będzie najbardziej pożądaną sytuacją, najmniej pracochłonną programistycznie.

Rzeczywiste, rozproszone systemy informatyczne składają się jednak z wielu różnych elementów

zbudowanych przy użyciu setek technologii pojawiających się i znikających na przestrzeni lat.

Ze względu na koszty, jakie ponoszą organizacje przy wdrażaniu poszczególnych składników takich

systemów, ich przepisanie w nowym języku programowania, a często nawet drobna modyfikacja,

jest zwykle nierealne. Oznacza to, iż wirtualne repozytorium musi posiadać możliwość integracji

zasobów spadkowych o heterogenicznym charakterze. Cel ten zostanie zrealizowany zgodnie

z regułami przyjętymi dla federacyjnych baz danych. Zaprojektowany zatem zostanie kanoniczny

model danych zdolny reprezentować popularne modele danych wykorzystywanych we

współczesnych bazach danych i językach programowania. Ten kanoniczny model danych

obowiązywać będzie w całym wirtualnym repozytorium, a każdy integrowany zasób (np. relacyjna

baza danych) będzie mógł być wyrażany w jego kategoriach za pomocą zestawu osłon (adapterów)

lub filtrów (importerów). Dodatkowe różnice w schematach poszczególnych żródeł danych oraz

20

Page 21: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

reprezentacji danych (np. różne waluty) rozwiązywane będą za pomocą aktualizowalnych

perspektyw pełniących rolę mediatorów. W szczególności, osobna taka perspektywa będzie mogła

zostać zdefiniowana dla każdego systemu kontrybuującego do repozytorium (tzw. perspektywa

kontrybucyjna) oraz globalna perspektywa prezentująca zawartość całego systemu jako wirtualną

całość (tzw. perspektywa integracyjna). Globalny użytkownik korzystał będzie z repozytorium za

pomocą jednego języka zapytań (rozszerzonego do języka programowania), niezależnie od tego

gdzie fizycznie znajdować się będą integrowane dane/usługi, oraz jakie technologie zostały użyte

do ich wygenerowania. Ponieważ tak utworzona rozproszona baza danych widziana jest przez

zewnętrznego użytkownika jako pojedyncza, wirtualna baza danych, istnieje także możliwość

zbudowania dla niej tradycyjnych interfejsów dostępowych, np. JDBC, czy WebServices. W ten

sposób, technologia ta zgodna będzie z przyjętymi w przemyśle standardami, ale jednocześnie

niezależna od nich. W niniejszej pracy nie będziemy jednak zajmowali się konstrukcją takich

interfejsów dostępowych, ani (w szczególności) wrapperów. Konstrukcja takich modułów (np.

osłony do relacyjnej bazy danych) jest zadaniem nietrywialnym i stanowi treść osobnych prac

doktorskich.

Język programowania/zapytań zaproponowany w rozprawie bazuje na podejściu stosowym (Stack-

Based Approach, SBA) do języków zapytań. SBA jest semantyczną ramą ułatwiającą budowę

mocnego języka zapytań dla praktycznie dowolnego znanego modelu danych, niezależnie od tego

czy jest to model półstrukturalny (np. XML), ustrukturalizowany (np. relacyjna baza danych), czy

nieustrukturalizowany (np. dane multimedialne). Przykładowo, obsługa danych XML zapewniona

jest poprzez możliwość zaimportowania zawartości dowolnego dokumentu do bazy

danych i wyrażenia jego treści w terminach obiektów tej bazy danych. Na takich danych można

następnie pracować w taki sposób, jak gdyby były to natywne dane zdefiniowane za pomocą języka

definicji danych wbudowanego w SZBD.

Budowa kompletnego języka programowania bezszwowo zintegrowanego z konstrukcjami języka

zapytań możliwa jest dzięki temu, iż w podejściu stosowym zapytania traktowane są tak, jak

wyrażenia w tradycyjnych językach programowania. Semantyka zapytań jest zatem oparta na

mechanizmach dobrze znanych z typowych języków - stosie środowisk, stosie arytmetycznym oraz

paradygmacie nazwa-zakres-wiązanie. Pozwala to na precyzyjne określenie semantyki operacyjnej

języków zapytań z uwzględnieniem cech obiektowości (np. klasy, dynamiczne role obiektów),

konstrukcji imperatywnych i abstrakcji programistycznych (np. procedur, perspektyw, modułów).

21

Page 22: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Wykorzystanie SBA umożliwi nam znaczną redukcję liczby języków, z jakimi ma do czynienia

typowy programista baz danych. W idealnej sytuacji może to być jeden język przeznaczony do

programowania aplikacji, definiowania schematu bazy danych, wykonywania zapytań,

transformowania danych, itd.

Najważniejsze aspekty technologii zaprezentowanej w rozprawie zaimplementowane zostały

w postaci prototypu. Jest on podstawowym komponentem systemów e-GovBus oraz VIDE,

realizowanych przez PJWSTK wspólnie z partnerami, oraz finansowanych w ramach grantów

przyznanych przez Unię Europejską.

Teza rozprawy doktorskiejKoncepcja wirtualnego repozytorium oparta na jednorodnym obiektowym środowisku

programistycznym bazującym na języku zapytań zintegrowanym z językiem programowania jest

alternatywą dla wielu obecnie popularnych, eklektycznych technologii. Koncepcja ta potwierdzona

została poprzez stworzone oprogramowanie. Jest ono zatem dowodem tezy naukowej dektoratu

mówiącej o tym, iż jest możliwe stworzenie metodologii oraz odpowiednich dla niej narzędzi

programistych (opartych o zintegrowany język zapytań/programowania), które pozwalą na szybką

i tanią budowę wirtualnego repozytorium opartego o kanoniczny model obiektowy. Zadaniem

takiego repozytorium jest integracja danych i aplikacji znajdujących się pod kontrolą tych samych

lub niezależnych od siebie organizacji, a także umożliwienie szybkiego programowania wydajnych

aplikacji baz danych na bardzo wysokim poziomie abstrakcji.

PodsumowanieW rozdziale krótko przedstawiliśmy problemy wiążące się z integracją danych i aplikacji

w systemach rozproszonych. Przedstawiliśmy w nim nasze stanowisko mówiące o tym, iż

obiektowa baza danych z wbudowanym językiem zapytań zintegrowanym z językiem

programowania stanowi potencjalne narzędzie do budowy zintegrowanych baz danych oraz ich

aplikacji. Dzięki pełnej mocy obliczeniowej porównywalnej z istniejącymi językami

programowania, obiektowa baza danych tego typu jest w stanie przykryć funkcjonalnością dowolny

istniejący współcześnie rodzaje middleware, a także niektóre języki programowania czwartej

generacji. Poprzez zastosowanie w pełni aktualizowalnych perspektyw, system tego typu może

również służyć do budowy federacyjnych baz danych. Tak zbudowana baza danych pozbawiona

jest dwóch poważnych problemów związanych z takimi bazami danych jeśli realizowane są przy

użyciu relacyjnych baz danych:

22

Page 23: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

1. uproszczonego modelu danych implikowanego przez relacyjny model danych,

2. braku możliwości aktualizacji sfederowanych zasobów danych od strony globalnego klienta.

Przedstawiliśmy również cel niniejszej pracy doktorskiej, której zamierzeniem jest zaprojektowanie

architektury obiektowej bazy danych nowego typu, jak również zaimplementowanie jej prototypu.

23

Page 24: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp
Page 25: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdział 2:Stan sztuki w dziedzinieintegracji danych i aplikacji

WprowadzenieW bieżącym rozdziale krótko omówimy najważniejsze teorie, techniki, technologie i inne

rozwiązania związane z integracją danych i aplikacji. Ponieważ w niniejszej pracy będziemy

dowodzili, iż obiektowa baza danych jest doskonałym narzędziem dla EAI/EII, zanim przejdziemy

do dokładniejszego opisu naszej koncepcji, postaramy się pokazać dlaczego naszym zdaniem

istniejące techniki programowania aplikacji baz danych powinny zostać w dużej części

przedefiniowane. W naszym opisie skoncentrujemy się na trzech aspektach integracyjnych:

integracji języków programowania z bazami danych za pomocą języków zapytań, metodach

zapewniania komunikacji pomiędzy heterogenicznymi aplikacjami, oraz deklaratywnych sposobach

integracji różnorodnych baz danych.

Integracja baz danych z językami programowaniaMetody integracji języków programowania z bazami danych studiowane są od wielu lat. W związku

z tym, iż ogólnie przyjętym mechanizmem operowania na bazach danych jest język zapytań,

integracja baz danych z językami programowania wiąże się zazwyczaj z integracją języka

imperatywnego ogólnego przeznaczenia z językiem deklaratywnym operującym na bazie danych.

25

Page 26: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Najbardziej popularna klasyfikacja metod integracji języków programowania z bazami danych

oparta jest na dwóch metodach. Pierwsze z tych podejść, tzn. zanurzanie jako literałów kodu języka

zapytań w kodzie języka programowania, obarczone są poważną wadą znaną pod nazwą

“niezgodność impedancji”. Alternatywne podejścia (np. Pascal/R [43], Napier88 [44], DBPL [41],

LOQIS [31], Fibonacci [28], Oracle PL/SQL) w dużym stopniu pozbawione są tej wady, ponieważ

dążą one do stworzenia jednolitego środowiska programistycznego, a konstrukcje imperatywne

zintegrowane są z konstrukcjami deklaratywnymi.

Poniżej przedstawimy krótki, krytyczny opis najbardziej znanych podejść w dziedzinie integracji

języków zapytań z językami programowania.

Interfejs poziomu wywołań

Najbardziej znanym sposobem dostępu do baz danych jest tzw. interfejs poziomu wywołań (Call

Level Interface, CLI). Technika ta polega na zagniedżaniu kodu języka zapytań odpowiedzialnego

za operacje realizowane na bazie danych jako literały łańcuchów znaków w kodzie źródłowym

programów napisanych w językach proceduralnych, a następnie użyciu pewnej bazodanowej

warstwy pośredniej (database middleware) dostępnej jako API.

Poniższy kod w języku Java ilustruje sposób korzystania z interfejsu poziomu wywołań. Fragment

ten odpowiedzialny jest za wysłanie zapytania SELECT * FROM MyTable do bazy danych, a następnie

wyświetlenie na ekranie wszystkich wierszy i kolumn tabeli wynikowej.

Statement stmt = conn.createStatement();try { ResultSet rs = stmt.executeQuery("SELECT * FROM MyTable"); try { while (rs.next()) { int numColumns = rs.getMetaData().getColumnCount();

for (int i = 1 ; i <= numColumns ; i++) System.out.println("COLUMN " + i + " = " + rs.getObject(i)); }

} finally { rs.close(); }

} finally { stmt.close();}

Na przestrzeni lat podejście takie zostało mocno skrytykowane jako uniemożliwiające statyczną

kontrolę typów zapytań (literały Javy nie są dostępne dla kompilatora SQL), wymagające konwersji

26

Page 27: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

typów języka programowania na typy bazy danych, stanowiące zagrożenie dla bezpieczeństwa

systemu (tzw. sql injection), uniemożliwiające operacje wspomagania programowania realizowane

przez środowiska programistyczne (refaktoryzacja, podpowiadanie nazw) i inne. Niedogodności te

próbowano ominąć wprowadzając dodatkowy etap kompilacji za pomocą tzw. prekompilatora (np.

SQLJ), analizującego specjalne bloki kodu źródłowego z zawartością będącą kodem

rozpoznawanym przez prekompilator. Prekompilator zdolny jest analizować wnętrze takich

specjalnych klauzul, kontrolować poprawność odwołań zarówno do Javy, jak i do bazy danych,

a także automatycznie zamieniać wnętrze tych klauzul na odpowiednie wywołania CLI

(w przypadku SQLJ na kod Javy używający JDBC). Niestety okazało się że podejście to jest

niewystarczające.

Języki z trwałością

Języki z trwałością należą do dosyć istotnego nurtu bliskiego bazom danych. Aczkolwiek

eksperymentalne projekty (np. Fibonacci [28], PS-Algol [57], DBPL [41], Napier88 [44],

Machiavelli [46], PJama [23], i in.) stworzone w ubiegłej dekadzie nie zdobyły popularności poza

laboratoriami w których powstały, odegrały one silny wpływ na architekturę obiektowych baz

danych. Języki te były zwykle rozszerzonymi tradycyjnymi językami programowania (np. PJama

jest rozszerzeniem Javy, a DBPL Moduli2) wprowadzającymi pojęcie trwałych zmiennych/

obiektów. Trwała zmienna to taka, która ma wszystkie własności zmiennej języka programowania,

ale zachowuje swoją wartość pomiędzy kolejnymi uruchomieniami programu. Uważano że dzięki

takiemu podejściu dowolne bazy danych można traktować jako zestawy trwałych zmiennych.

Prawdopodobnie najpoważniejszym wkładem tych języków w dziedzinę obiektowych baz danych

stało się pojęcie ortogonalnej trwałości. Koncepcja ortogonalnej trwałości mówi, iż programista

nigdy nie powinien być zmuszany do tworzenia kodu odpowiedzialnego za przenoszenie danych

pomiędzy trwałym i ulotnym składem danych. Zakładająca pełną unifikację definicji i środków

manipulacji trwałymi i ulotnymi danymi, koncepcja ta stanowiła ogromny postęp w zakresie

abstrakcji i estetycznego domknięcia pojęć. Przykładowo, projekt PJama zakładał, iż programista

nie musi w ogóle korzystać z żadnego API zapewniającego trwałość, gdyż jest ona zapewniana na

poziomie systemowym i dotyczy wszystkich zmiennych globalnych. System zapewnia zatem iluzję

ciągłej pracy oprogramowania, nawet pomimo zamierzonych lub niezamierzonych wyłączeń.

Cel ten próbowano osiągnąć poprzez rozszerzenie funkcjonalności wirtualnej maszyny języka Java

w taki sposób, aby w trakcie wystąpienia tzw. punktu kontrolnego bieżący stan aplikacji

27

Page 28: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

(danych i procesów) był utrwalany. Utrwalone zostają jedyne te dane, które od czasu ostatniego

punktu kontrolnego zostały zmodyfikowane. Gdy nastąpi punkt kontrolny, system jest zamrażany,

a wirtualna maszyna analizuje całe drzewo obiektów sterty w poszukiwaniu takich obiektów.

Po zatrzymaniu aplikacji i jej ponownym uruchomieniu tak zmodyfikowana maszyna potrafi

kontynuować przetwarzanie od momentu w którym jego stan został utrwalony w trakcie ostatniego

punktu kontrolnego.

W innych językach z trwałością stosowano mniej lub bardziej podobne metody utrwalania danych.

W większości projektów koncentrowano się na zbudowaniu nowego języka (często z bardzo

wymyślną semantyką i systemem typów), albo rozszerzeniu istniejącego o aspekt trwałości,

całkowicie ignorując wiążące się z tym implikacje wynikające z konieczności przetwarzania danych

masowych. Żaden ze stworzonych w ten sposób języków nie pozwalał na wykorzystywanie typowo

bazodanowych konstrukcji, np. indeksów, perspektyw, czy wyzwalaczy. Większość języków

z trwałością nie obsługuje również innych krytycznych dla baz danych mechanizmów, np.

transakcji, dzienników, dynamicznej optymalizacji, współbieżnego dostępu wielu równoległych

sesji, kont użytkowników, uprawnień, itd. Tylko w niewielkiej grupie języków wprowadzone

zostały konstrukcje deklaratywne, niezbędne do wygodnego operowania na danych masowych.

Niestety, zazwyczaj konstrukcje te były nieortogonalne z resztą języka. Przykładowo, w systemie

DBPL można korzystać z języka zapytań, ale tylko w stosunku do specjalnego rodzaju zmiennych

zadeklarowanych jako (zagnieżdżone) relacje (próba połączenia języka programowania z modelem

relacyjnym). Wyjątkiem był tu jedynie system Loqis [30, 31], w którym przyjęto jednak zupełnie

inne założenia. Zamiast rozszerzać język proceduralny o konstrukcje charakterystyczne dla baz

danych, rozszerzono bazę danych oraz jej język zapytań o konstrukcje charakterystyczne dla

proceduralnych języków programowania. Dosyć podobne podejście (aczkolwiek

w nieporównywalnie mniejszym stopniu) dotyczy języka PL/SQL firmy Oracle.

Odwzorowanie relacyjno-obiektowe

Odwzorowanie relacyjno-obiektowe jest innym rodzajem integracji aplikacji z bazą danych. Celem

tej techniki jest stworzenie “wirtualnej obiektowej bazy danych” na bazie relacyjnej bazy danych

oraz obiektowego języka programowania. Zdaniem zwolenników tej metody umożliwia to

wykorzystanie istniejących relacyjnych baz danych i obiektowych języków programowania

w sposób “obiektowy”, czyli bez pracochłonnego tłumaczenia struktur relacyjnych na struktury

28

Page 29: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

obiektowe. Rozwiązanie to zapewnia zatem iluzję języka z trwałością korzystającego

z dobrodziejstw relacyjnej bazy danych.

Prawdopodobnie najbardziej znaną obecnie technologią tego rodzaju jest Hibernate [20]. Praca

z Hibernate polega na stworzeniu jednej lub kilku klas Javy, których struktura jest następnie

opisywana za pomocą plików XML. Każda taka klasa posiada przypisaną tabelę w bazie danych,

a każdy jej atrybut odpowiednią kolumnę. Stworzone w ten sposób klasy określane są jako trwałe,

ponieważ Hibernate automatycznie utrwala w bazie danych wszystkie zmiany w stanie obiektów

będących instancjami takich klas. Oprócz atrybutów odpowiadających kolumnom tabeli relacyjnej,

każda trwała klasa powinna posiadać atrybut id, w kórym Hibernate zapisuje wartość klucza

głównego dla danego wiersza tabeli. Podczas operacji aktualizacyjnych pozwala to zapisać w bazie

danych zmiany w stanie obiektu wprowadzone na poziomie Javy. Operacje na bazie danych

realizowane są za pomocą obiektu klasy Session, która reprezentuje połączenie z serwerem. Obiekt

trwałej klasy utworzony z poziomu Javy zapisywany jest w bazie danych za pomocą metody save()

tej klasy. Operacja taka powoduje utworzenie wiersza w tabeli bazy danych z którą związana

została dana klasa trwała za pomocą odpowiedniego wpisu wyrażonego w XML. Wpis ten

wykorzystywany jest przez Hibernate do skonstruowania odpowiedniej instrukcji SQL przesyłanej

do bazy danych. Za pomocą mechanizmu refleksji wyznaczana jest nazwa trwałej klasy, a następnie

wyszukiwana jest odpowiednia pozycja wiążące tę klasę i jej atrybuty z odpowiednią tabelą bazy

danych i jej kolumnami. Jeśli w tabeli bazy danych dla której przypisano klasę trwałą istnieje już

jakiś wiersz, wówczas obiekt klasy trwałej może zostać łatwo skonstruowany za pomocą metody

load() jeśli znana jest wartość klucza głównego tego wiersza. Po załadowaniu z bazy danych, stan

obiektu e odzwierciedla stan odpowiedniego wiersza bazy danych:

Employee e = (Employee) sess.load(Employee.class, id);

Niestety, jeśli wartość klucza głównego nie jest znana, wówczas konieczne jest albo załadowanie

wszystkich obiektów z bazy danych (przetwarzane mogą być następnie za pomocą iteratora [29]),

albo wykorzystanie języka zapytań. Sytuacja komplikuje się również wówczas, jeśli obiekt

ładowany za pomocą metody load() posiada zdefiniowane asocjacje z innymi obiektami (które być

może powiązane są własnymi asocjacjami z jeszcze innymi obiektami). W sytuacji takiej narzędzia

odwzorowania O/R nie są w stanie automatycznie ustalić czy obiekty będące celem asocjacji

powinny zostać załadowane razem z głównym obiektem, czy też dopiero przy pierwszej próbie

dostępu do powiązanego obiektu. Hibernate wymaga w takiej sytuacji jawnego określenia

pożądanego zachowania przez programistę.

29

Page 30: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Jeśli stan obiektu klasy trwałej zostanie zmodyfikowany, wówczas automatycznie konstruowane

jest polecenie update trafiające do bazy danych, wysyłane następnie do bazy danych. Hibernate

posiada własny mechanizm transakcji, niezależny od mechanizmu transakcji docelowej bazy

danych. Jeśli transakcja Hibernate zostanie zatwierdzona, dopiero wówczas może być

zainiacjalizowana transakcja bazy danych. Jeżeli z poziomu języka programowania zmodyfikowano

wiele obiektów, wówczas dla każdego takiego obiektu wygenerowane musi być osobne polecenie

update. Jeśli w ramach transakcji zmodyfikowano wiele obiektów, wówczas do bazy danych trafia

tyle poleceń update ile obiektów zostało zmodyfikowanych. Nie jest to zatem dobra metoda na

realizowanie operacji typu zwiększ pensję każdego pracownika o 1000 złotych. Na szczęście do

realizowania makroskopowych operacji imperatywnych Hibernate umożliwia bezpośrednie

wykorzystanie języka SQL (w sposób podobny do CLI).

Oprócz bezpośredniego wykorzystania SQL, programista może wyszukiwać dane w bazie danych

za pomocą języka HQL oraz niskopoziomowego API podobnego do S.O.D.A (tzw. query by API).

HQL jest językiem wewnętrznym Hibernate podobnym do SQL, ale uwzględniającym niektóre

mechanizmy obiektowości (np. dziedziczenie). HQL jest znacznie prostszym językiem

w porównaniu do SQL, nie umożliwia również wykorzystania rozszerzeń wprowadzonych

w niektórych systemach zarządzania bazami danych (np. wskazówek optymalizatora).

W przypadkach, gdy niezbędne są takie konstrukcje języka zapytań, których nie ma w HQL,

programista zmuszony jest korzystać z SQL. Zarówno SQL, jak i HQL zanurzane są w języku Java

jako literały łańcuchów znaków, a ich wyniki przetwarzane za pomocą iteratorów [29]. Jeśli

zapytanie ma zwracać tylko niektóre kolumny, albo kolumny nie istniejące fizycznie w bazie

danych (np. rezultaty funkcji agregujących), wówczas wyniki zapytań muszą być przetwarzane

pojedynczo, w sposób równie pracochłonny jak w przypadku CLI.

Twórcom Hibernate nie udało się całkowicie ukryć różnic pomiędzy relacyjną bazą danych

a obiektowym językiem programowania. Pomimo iż dzięki mapowaniu obiektów na tabele

relacyjne udało się nieco zniwelować niezgodność impedancji na poziomie modeli danych, operacja

taka nie przynosi wielkich korzyści, jeśli niezgodność ta nadal istnieje na poziomie języka

programowania. Większość operacji w każdej bazie danych realizowana jest za pomocą języka

zapytań, tymczasem technologie O/R nie wprowadzają żadnych ułatwień w ich obsłudze z poziomu

języka programowania. Naszym zdaniem technologie te wprowadzają kolejną warstwę złożoności

30

Page 31: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

w aplikacjach, zupełnie nie rozwiązując problemu integracji języków programowania z bazami

danych.

Obiektowe bazy danych a standard ODMG

Obiektowe bazy danych najczęściej kojarzone są ze standardem ODMG [27]. Standard ten pojawił

się w 1993 roku jako zbiór specyfikacji mających umożliwić programistom wytwarzenie

przenośnych aplikacji korzystających z obiektowych baz danych. Ostatnia wersja standardu o

numerze 3.0 została wydana w 2000 roku, po czym grupa ODMG uległa rozwiązaniu. Standard

obejmował następujące elementy:

• ramową architekturę systemu zarządzania obiektową bazą danych,

• model obiektowy, języki specyfikacji schematu (ODL),

• obiektowy język zapytań (OQL),

• wiązania do kilku popularnych języków programowania.

Standard nie znalazł szerszego uznania ze względu na jego istotne braki koncepcyjne i semantyczne

[26]. Wady modelu danych oraz języków ODL i OQL są dobrze znane, zatem nie będziemy ich

tutaj przytaczać. Z punktu widzenia integracji aplikacji z bazą danych największe znaczenie ma dla

nas zaproponowany przez ODMG sposób tworzenia aplikacji baz danych.

Wg standardu ODMG aplikacje baz danych powinny być tworzone w językach programowania

ogólnego przeznaczenia. Przykładowo, dla języka C++ standard przewiduje mechanizm wiązania

z bazą danych oparty o bibliotekę klas i funkcji umożliwiających przetwarzanie zawartości bazy

danych. Semantyka C++ jest rozszerzona w tym celu poprzez wykorzystanie mechanizmu

przeciążania operatorów. Wiązanie respektuje składnię i semantykę C++ oraz rozszerza system klas

języka C++ o klasy dotyczące trwałych obiektów. Wiązanie zakłada również zunifikowany system

typów dla trwałych i nietrwałych obiektów.

Procedura tworzenia aplikacji przebiega w kilku krokach. Programista dostarcza opis schematu

bazy danych zapisanego w języku ODL. Przykładowo, może to być plik o następującej treści:

interface Profesor : Osoba (extent profesorowie keys id_wydziału, nr_pesel): persistent { attribute char id_wydziału[6]; attribute long nr_pesel; attribute Adres adres; attribute set<string> stopnie; relationship set<Student> opiekuje_się inverse Student::opiekun;

31

Page 32: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

relationship set<Asystent> zatrudnia inverse Asystent::pracuje_dla; relationship Wydział pracuje_na inverse Wydział::zatrudnia; short Promuje( in string kogo ) raises (Nie_spełnia_warunków); };

Powyższy fragment deklaruje interfejs Profesor dziedziczący z Osoba. Interfejs ten określa

zewnętrzną charakterystykę obiektów danego typu widoczną dla użytkownika obiektu. Ustala także

atrybuty obiektu, operacje jakie można na nim wykonać, jak i związki z innymi obiektami.

W powyższym przykładzie wyspecyfikowano również nazwę pod którą będzie dostępna ekstensja

obiektów zgodnych z interfejsem Profesor.

Standard ODMG zakłada, że po zadeklarowaniu takiego interfejsu trafia on do kompilatora ODL.

Kompilator ten realizuje dwie operacje. Po pierwsze, deklarcje ODL trafiają do bazy danych, gdzie

definowane są wewnętrzne struktury potrzebne do przechowywania obiektów. Po drugie,

kompilator ODL generuje zbiór plików zawierających kod źródłowy sformułowany w języku

programowania którego dotyczy dane wiązanie językowe (np. C++). Pliki te zawierają zbiór

procedur umożliwiających korzystanie z zawartości bazy danych z poziomu języka programowania

w taki sposób, aby obiekty bazy danych były dla programisty nieodróżnialne od obiektów danego

języka programowania. Tak zbudowana aplikacja jest następnie kompilowana i konsolidowana

z kliencką biblioteką czasu wykonania dostarczaną przez dany SZBD.

Programista aplikacji klienckiej może operować na obiektach bazy danych w taki sam sposób, jak

gdyby operował na obiektach języka programowania w którym tworzy aplikację. Ponieważ modele

danych bazy danych oraz języka programowania są obiektowe, dlatego nie ma konieczności

tłumaczenia danych pomiędzy tymi modelami. Zauważmy jednak, że aby można było w ten sposób

operować na obiektach bazy danych, muszą one zostać najpierw wyszukane w bazie danych oraz

skopiowane do przestrzeni adresowej języka programowania. W ODMG do tego celu służy język

zapytań podobny do SQL, ale noszący nazwę OQL. Rozbieżności między OQL i SQL dotyczą

pojęć obiektowych, takich jak złożone obiekty, tożsamość obiektów, wyrażenia ścieżkowe,

polimorfizm, wołanie operacji, późne wiązanie. OQL nie jest jednak kompletny obliczeniowo.

Istnieją zapytania których nie można w nim zadać, nie posiada konstrukcji aktualizacyjnych,

abstrakcji programistycznych, ani konstrukcji sterujących.

Zapytania OQL są zatem zagnieżdżane w kodzie źródłowym języka programowania, a ich wyniki

przetwarzane są za pomocą iteratorów. Niestety, ponieważ standard ODMG nie przewiduje

konstrukcji imperatywnych, w których można byłoby zanurzyć zapytania OQL, dlatego

32

Page 33: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

aktualizacje nie mogą być wykonywane makroskopowo. Oznacza to, że kliencka biblioteka czasu

wykonania musi śledzić obiekty które zostały zmodyfikowane i wprowadzać pojedynczo

poszczególne modyfikacje do bazy danych. Jest to zatem poważny problem optymalizacyjny,

bardzo dotkliwy w architekturze klient-serwer.

Przy podejściu zgodnym z ODMG niezgodność impedancji między bazą danych a językiem

programowania nadal istnieje. W rzeczywistości naszym zdaniem problem staje się nawet bardziej

dotkliwy niż w przypadku relacyjnych baz danych programowanych za pomocą CLI. Operacje jakie

musi wykonać programista aby zaprogramować aplikację bazy danych wykorzystując wiązanie do

istniejącego języka programowania są dużo bardziej złożone niż w przypadku baz relacyjnych.

Naszym zdaniem to, oraz szereg poważnych wad koncepcyjnych i semantycznych w specyfikacji

standardu ODMG stało się przyczyną jego znikomej popularności. Niemniej trzeba autorom

przyznać, że mimo wad standard ten stał się osią i punktem odniesienia w przyszłych dyskusjach

dotyczących obiektowych baz danych.

Pomimo wad standardu ODMG najważniejsze decyzje w nim podjęte znajdowały swoje

odzwierciedlenie w różnych formach przez kolejne przedsięwzięcia związane z obiektowymi

bazami danych. Przykładem systemu który bazuje na podobnych założeniach (a nawet

implementuje część standardu ODMG) jest system Objectivity/DB. Cechą najbardziej

charakterystyczną dla produktów zainspirowanych standardem ODMG jest przekonanie,

iż obiektowa baza danych powinna być rozszerzeniem popularnego obiektowego języka

programowania.

Inne rodzaje obiektowych baz danych

Interesującą alternatywą w stosunku do wielu elementów standardu ODMG jest system db4o oraz

jego mechanizm operowania na bazie danych noszący nazwę native queries [13]. W założeniu

twórców tego rozwiązania, native queries powinno usunąć niezgodność impedancji na poziomie

języka programowania oraz języka operowania na bazie danych poprzez realizację konstrukcji

przypominających język zapytań, ale wyrażonych za pomocą języka Java lub C#. Mechanizm ten

reklamowany jest jako 100% typesafe, 100% compile-time checked and 100% refactorable.

Spójrzmy na proste zapytanie napisane z użyciem native queries, pochodzące z dokumentacji

systemu db4o:

List <Pilot> pilots = db.query(new Predicate<Pilot>() {    public boolean match(Pilot pilot) {

33

Page 34: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

        return pilot.getPoints() == 100;    }});

“Zapytanie” to ma za zadanie odszukać wszystkich kierowców formuły 1 (pilotów), którzy zdobyli

100 punktów. W tym celu tworzona jest instancja anonimowej klasy implementującej interfejs

Predicate, deklarujący metodę match(). Po zainicjowaniu ewaluacji zapytania, metoda match()

zostanie wywołana dla każdego obiektu klasy Pilot. Jeśli dla danego kierowcy metoda zwróci true,

wówczas reprezentujący go obiekt znajdzie się w kolekcji wynikowej, jeśli false - to nie.

Prostota tego założenia być może dobrze sprawdza się w niszowych zastosowaniach, takich jak

systemy wbudowane, naszym jednak zdaniem nie może stać się podstawą poważnego systemu

zarządzania obiektową bazą danych. Naszą uwagę zwraca przede wszystkim ubogość możliwych

operacji jakie można wyrazić za pomocą “zapytań” sformułowanych z użyciem native queries.

Zbiór możliwych operacji ogranicza się praktycznie jedynie do selekcji - brak jest możliwości

tworzenia złączeń, projekcji, kwantyfikatorów, agregowania, operacji zbiorowych (union, minus,

intersect, etc,.), i wielu innych, uważanych za podstawowe operacje w SQL. Nie jest możliwe

również tworzenie zapytań ad-hoc - każde, nawet najprostsze zapytanie musi być częścią aplikacji.

Najpoważniejszy problem z native queries wiąże się jednak z optymalizacją zapytań. Większość

znanych metod optymalizacyjnych w językach zapytań bazuje na przepisywaniu. Do bazy danych

trafia treść zapytania (jako tekst), po czym jest ono przetwarzane na równoważną semantycznie

postać, która jest jednak wydajniejsza w ewaluacji. Ponieważ w przypadku native queries nie mamy

do czynienia z tekstem zapytania, optymalizacja taka jest znacznie utrudniona, o ile w ogóle

możliwa. W związku z tym, iż treścią metody match() może być absolutnie dowolny kod Javy, nie

bardzo wiadomo w jaki sposób zbudować na jego podstawie tekstową formę zapytania, która

mogłaby trafić do serwera bazy danych i być tam zoptymalizowana. Obecne implementacje próbują

optymalizować zapytania poprzez analizę kodu pośredniego, co naszym zdaniem w ogólnym

przypadku jest niewykonalne. Praktycznie wszystkie znane metody optymalizacji zapytań pracują

na deklaratywnej formie zapytania, a nie na skompilowanej, niskopoziomowej postaci.

Wszystkie te problemy wzmacniają nasze przekonanie o tym, iż native queries nie są odpowiedzią

na problem integracji języków zapytań z językami programowania i mogą znaleźć zastosowanie

jedynie w bardzo niszowych zastosowaniach. Dotyczy to również innych technologii działających

w podobny sposób, np. Linq [45] oraz Cω [44] firmy Microsoft.

34

Page 35: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Integracja rozproszonych danych i aplikacjiJedną z cech współczesnych organizacji jest to, iż różne ich jednostki organizacyjne używają

różnych systemów do tworzenia, przechowywania i przeszukiwania danych mających dla nich

jakieś znaczenie. Różnorodność źródeł danych wiąże się z brakiem koordynacji, różnym tempem

adoptowania nowych technologii, geograficznym oddaleniem, jak i łączeniem się ze sobą różnych

firm. Jedynie poprzez integrację tych wszystkich systemów organizacje mogą skorzystać z pełnej

wartości należących do nich danych. Wraz z rozwojem systemów informatycznych oraz sieci

Internet, coraz częściej mówi się również o integracji aplikacji - zarówno należących do tego

samego przedsiębiorstwa (Enterprise Application Integration, EAI), jak i różnych organizacji

(Business To Business, B2B) [3, 11].

Rozproszone obiekty

Integracja danych i aplikacji może być realizowana na poziomie fizycznym za pomocą wielu

różnorodnych technik. Ze względu na dążenie do zmniejszenia kosztów wytwórczych

oprogramowania, obecnie odchodzi się raczej od implementacji własnych, specyficznych dla

konkretnych systemów protokołów, dążąc do wykorzystania istniejącego już, uniwersalnego

oprogramowania ułatwiającego komunikację między aplikacjami - tzw. middleware. Na przestrzeni

lat zaprojektowano wiele rodzajów middleware: rozproszone obiekty, serwery aplikacyjne, kolejki

komunikatów, serwery integracyjne, monitory transakcyjne, i in. Różne rodzaje middleware

pozwalają wykorzystać różne strategie integracyjne (integracja zorientowana na dane, na usługi, na

komunikaty, na procesy biznesowe, poprzez portale itd.), wykorzystując do tego celu różnego

rodzaju metody łączenia integrowanych elementów (połączenia point-to-point, albo many-to-many)

oraz scenariusze komunikacji (komunikacja synchroniczna i asynchroniczna).

Jednym z bardziej znanych rodzajów middleware są rozproszone obiekty, których prawdopodobnie

najbardziej znanym reprezentantem jest standard CORBA [25, 102]. Rozproszone obiekty

definiowane są w tym standardzie jako fragmenty większych aplikacji, zaprojektowanych do

wzajemnej współpracy, jednak działającymi na zupełnie odrębnych maszynach. Podstawowymi

zaletami rozproszonych obiektów są: obiektowy model danych, zgodność z logiką biznesu,

stusunkowo wysoki poziom abstrakcji, szereg usług (np. transakcyjność) dostępnych dla

programistów, standardowy protokół wymiany danych pomiędzy elementami systemu

rozproszonego, niezależność od użytego w implementacji języka programowania.

35

Page 36: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Programista tworzący aplikację opisuje jej interfejs dostępny dla zdalnych klientów za pomocą

specjalnego, niezależnego od implementacji języka - IDL (Interface Definition Language). Poniżej

zaprezentowano przykład takiej definicji:

module StockObjects { struct Quote { string symbol; long at_time; double price; long volume; };

exception Unknown{};

interface Stock { Quote get_quote() raises(Unknown); void set_quote(in Quote stock_quote);

readonly attribute string description; };};

Pliki zbudowane za pomocą IDL poddawane są następnie działaniu kompilatora IDL, który

generuje kod dla wybranego języka programowania. Przykładowo, dla powyższego interfejsu

i języka Java, mogą zostać wygenerowane następujące pliki: Stock.java (interfejs Stock w postaci

interfejsu Javy), Quote.java (klasa Javy reprezentująca strukturę Quote), StockHelper.java,

QuoteHelper.java (implementacja pomocniczych operacji związanych z operowaniem na typach),

StockHolder.java, QuoteHolder.java (klasa pomocnicza umożliwiająca reprezentowanie w Javie

przekazywania parametrów w trybach in i out), _StockStub.java (klasa używana przez klienta jako

namiastka zdalnego klienta, w przypadku serwera jest ona rozszerzana o implementację zdalnych

operacji).

Głównym zadaniem wygenerowanego w ten sposób kodu jest umożliwienie przyłączenia tworzonej

aplikacji do tzw. obiektowego pośrednika żądań (Object Request Broker). Zadaniem takiego

pośrednika jest komunikacja z innymi brokerami (być może dostarczanymi przez innych

producentów), znajdującymi się na odrębnych maszynach, za pomocą standardowego protokołu

(np. Internet Inter-Orb Protocol, IIOP), zdefiniowanego w standardzie CORBA. Zbiór połączonych

ze sobą pośredników tworzy tzw. szynę CORBA.

Charakterystyczną cechą rozproszonych obiektów jest to, iż z punktu widzenia programisty

tworzącego aplikację kliencką nie ma różnicy w operowaniu na danych trwałych lub nietrwałych.

36

Page 37: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Niestety, z czasem okazało się iż ta unifikacja metod dostępu do danych oraz łatwość dostępu do

danych spowodowała u programistów pokusę ignorowania ograniczeń nakładanych przez sieć

komputerową (czas dostępu, awaryjność) i projektowanie aplikacji rozproszonych w taki sam

sposób, jak gdyby były to aplikacje nierozproszone. Przykładowo, naiwna implementacja operacji

przetworzenia kolekcji zdalnych obiektów w sposób proceduralny (za pomocą iteratorów) oznacza

wielokrotną wymianę danych między serwerem i klientem, proporcjonalną do ilości obiektów.

Ta cecha, w połączeniu z niespójnością samego standardu, złożonym API, niekompatybilnością

pomiędzy oprogramowaniem dostarczanym przez różnych dostawców i innymi poważnymi

problemami stała się przyczyną zmniejszającej się popularności standardu CORBA. Mimo

znaczących sukcesów (7 mln instalacji) standard CORBA podlega ostatnio druzgocącej krytyce, zaś

nowych instalacji praktycznie nie przybywa. Czy oznacza to jednak, że sama technologia

rozproszonych obiektów również skazana jest na porażkę?

Wydaje się, że zunifikowanie dostępu do danych lokalnych i zdalnych jest wadą wówczas, gdy

aplikacja tworzona jest w tradycyjnym języku programowania, gdzie dane przetwarzane są sposób

proceduralny. W takiej sytuacji, programista nie posiadający doświadczenia w tworzeniu

rozproszonych aplikacji tworzy niestabilne i niewydajne oprogramowanie. Programista posiadający

takie doświadczenie, ma z kolei ograniczone pole manewru w dziedzinie optymalizacji, ponieważ

może korzystać wyłącznie z metod zaimplementowanych przez twórcę aplikacji serwerowej.

W przypadku gdy odpowiednia metoda nie jest zaimplementowana, wówczas konieczne jest

przetwarzanie po stronie klienckiej (lub przebudowanie aplikacji serwerowej). W ramach standardu

CORBA stworzona została co prawda usługa zapytań, jednak nie znalazła ona uznania w oczach

specjalistów. Wraz z innymi usługami (np. usługą transakcyjności) dodaje ona dodatkowy poziom

złożoności do i tak już skomplikowanego standardu.

Pewna forma języka zapytań wprowadzona została w innej technologii - Enterprise Java Beans.

Technologia ta od samego początku zaprojektowana była w celu zapewnienia podstawowych usług

związanych trwałością, transakcyjnością i bezpieczeństwem w kontekście języka Java. Niestety,

zagadnienie trwałości rozwiązane jest w sposób podobny do Hibernate, czyli poprzez mapowanie

relacyjno obiektowe. Ponieważ sama technika tworzenia rozproszonych obiektów w środowisku

EJB jest również niezwykle skomplikowana, nie dziwi zatem głośna krytyka EJB ze strony wielu

specjalistów.

37

Page 38: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

W rzeczywistości złożoność API jest cechą praktycznie wszystkich współczesnych technologii

wspomagających tworzenie oprogramowania rozproszonego, niezależnie od tego czy jest to

CORBA [25], DCOM [101], EJB [52], Spring [105], JMS [104], czy WebServices [11]. Naszym

zdaniem przyczyną tego stanu rzeczy jest zbyt niski poziom abstrakcji oraz tworzenie

oprogramowania za pomocą tradycyjnych języków programowania, które są nieprzystosowane do

tego celu. Projektując zatem język programowania zintegrowany z językiem zapytań, warto zatem

zastanowić się nad wbudowaniem do niego odpowiednich konstrukcji wspierających komunikację

rozproszoną. Język taki powinien posiadać mechanizmy optymalizacyjne związane

z przetwarzaniem danych masowych w wolnym i niestabilnym środowisku rozproszonym.

Rozproszone i federacyjne bazy danych

Potrzeby niektórych organizacji (np. instytutów naukowo-badawczych) wymagają integracji

dostępnych w nich zasobów na bardzo niskim poziomie, tzn. poziomie prostych danych

składowanych w bazach danych. Dla organizacji takich integracja danych za pomocą usług, czy

z wykorzystaniem rozproszonych obiektów może być nieakceptowalna ze względu na ich zbyt

wysokopoziomowy charakter implikujący pewną “sztywność” w sposobie dostępu. Alternatywnym

rozwiązaniem może być budowa scentralizowanej bazy danych podobnej do hurtowni danych,

jednak rozwiązanie to może być nieakceptowalne ze względu na koszt, czas dostępu do najbardziej

aktualnej wersji danych danych, i in. Integracja zasobów kilku baz danych za pomocą federacji

może okazać się najbardziej bezinwazyjną metodą integracji systemów informatycznych (np.

w przypadku przejęcia jednej firmy przez drugą).

Federacyjna baza danych [47, 48] jest logicznym powiązaniem niezależnych od siebie,

rozproszonych baz danych, tworzącym pojedynczy, zintegrowany system bazodanowy. Integrowane

w ten sposób źródła danych mogą być nie tylko typowymi bazami danych (np. obiektowymi,

relacyjnymi, repozytoriami XML) różnorodnych producentów, ale również płaskimi plikami,

dokumentami tekstowymi, plikami arkuszy kalkulacyjnych, oraz wieloma innymi rodzajami danych

ustruktualizowanych i nieustrukturalizowanych. Architektura federacyjna powoduje że wszystkie te

dane widoczne są jako jedna, wirtualna całość (stąd czasem używana nazwa - wirtualna baza

danych).

Integrowane bazy danych udostępniają szereg swoich zasobów całej federacji. Zasoby te mogą być

metadanymi (schematy bazodanowe), zwykłymi danymi, czy interfejsami programistycznymi

umożliwiającymi korzystanie z takiej bazy danych. Suma udostępnionych w ten sposób danych

38

Page 39: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

razem z centralną, integracyjną bazą danych tworzy całą infrastrukturę federacyjną. Zintegrowane

bazy danych udostępniają część lub całość swojej zawartości innym członkom federacji, pozostając

jednak autonomię w ich lokalnym zarządzaniu.

Nowe źródła danych mogą być dodawane do federacji poprzez utworzenie dla nich tzw. osłon

(wrappers). Osłony są relatywnie nieskomplikowanymi, ale niskopoziomowymi programami

umożliwiającymi fizyczne połączenie z federacją różnorodnych, heterogenicznych źródeł danych.

Przykładowo, zadaniem osłony dla plików programu Microsoft Excel powinno być

zaimplementowanie pewnego API umożliwiającego odczytywanie tych plików i dynamicznym

udostępnianiu jego zawartości dla oprogramowania sterującego funkcjonowaniem federacyjnej

bazy danych (np. w formie sterownika JDBC) zgodnie z modelem danych przyjętym dla niej.

Architektura federacyjnej bazy danych często obejmuje także komponenty zwane mediatorami.

Mediator jest specjalnym modułem oprogramowania umieszczanym po stronie integrowanego

zasobu. Jego zadaniem jest takie przekształcenie lokalnych danych, by mogły być one

wykorzystane przez globalnego użytkownika zgodnie z pewnymi regułami przyjętymi dla całej

federacji. Mediator tłumaczy zapytanie zgodne z globalnym schematem federacji na taką jego

formę, by mogło być one wykonane na danych lokalnych. Oprócz przekształceń związanych

z różnymi schematami danych, przekształcane mogą być również same dane. Przykładem takiego

zastosowania mediatorów jest dynamiczna (wirtualna) konwersja pensji z waluty używanej lokalnie

(np. PLN) do waluty używanej w całej federacji (np. USD). Nawet taki wydawałoby się banalny

problem wymaga rozstrzygnięć i umów, np. ustalenia serwisu bankowego wg którego na bieżąco

będzie przeliczana waluta, czy zamiana aktualizacji wyrażonej w walucie obowiązującej

w federacji na walutę obowiązującą w lokalnej walucie.

Krytyczną cechą federacyjnych baz danych jest stopień w jaki system taki jest w stanie upodobnić

się do scentralizowanej bazy danych, oraz ukryć złożoność mechanizmów związanych z integracją

danych w heterogenicznym i rozproszonym środowisku. Najczęściej mówi się o następujących

poziomach przezroczystości w federacyjnych baz danych:

• Przezroczystość dostępu, czyli dostarczenie jednorodnych metod operowania na danych

lokalnych i odległych,

• Przezroczystość położenia, czyli uwolnienie użytkowników od konieczności posiadania wiedzy

na temat fizycznej lokalizacji danych w systemie rozproszonym,

39

Page 40: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• Przezroczystość współbieżności, czyli umożliwienie wielu użytkownikom jednoczesnego dostępu

do danych przy zachowaniu pełnej spójności danych, bez konieczności umawiania się, czy

niskopoziomowego programowania mechanizmów synchronizacyjnych,

• Przezroczystość heterogeniczności, czyli umożliwienie jednolitego traktowania danych

pochodzących z różnych źrodeł, zapisanych tam za pomocą różnych modeli danych,

• Przezroczystość skalowania, czyli umożliwienie dodawania nowych elementów systemu

rozproszonego bez wpływu na działanie starych aplikacji i pracę użytkowników,

• Przezroczystość fragmentacji, czyli automatyczne scalanie obiektów, tabel lub kolekcji, których

fragmenty przechowywane są w różnych miejscach,

• Przezroczystość replikacji, czyli umożliwienie tworzenia i usuwania kopii danych w innych

miejscach geograficznych z bezpośrednim skutkiem dla efektywności przetwarzania, ale bez

skutków dla postaci programów użytkowych lub pracy użytkownika końcowego,

• Przezroczystość optymalizacji, czyli możliwość wykorzystania bez wiedzy użytkownika szeregu

strategii optymalizacyjnych czasu kompilacji lub wykonania, umożliwiających przyspieszenie

wykonywania zapytań realizowanych na rozproszonej bazie danych,

• Przezroczystość awarii, czyli umożliwienie nieprzerwanej pracy większości użytkowników

rozproszonej bazy danych w sytuacji, gdy niektóre z jej węzłów lub linie komunikacyjne uległy

awarii,

• Przezroczystość migracji, czyli umożliwienie przenoszenia zasobów danych do innych miejsc bez

wpływu na pracę użytkowników,

• i in.

Federacyjne bazy danych na przestrzyni lat były przedmiotem wielu projektów badawczych, a także

kilku rozwiązań komercyjnych. Spośród pierwszych, pionierskich prób budowy takich baz danych

wymienić można systemy TSIMMIS [33] oraz HERMES. W obu tych systemach wykorzystano

koncepcje bazodanowe do implementacji “mediatorów” posługujących się nieproceduralnymi

specyfikacjami do integracji specyficznych źródeł danych. Systemy DISCO [49] i Pegasus [50] były

bliższe postaci współczesnych federacyjnych baz danych. Twórcy DISCO koncentrowali się na

wydajnej integracji zasobów heterogenicznych. Pegasus miał swój własny model danych oraz język

zapytań. System Garlic [56] był pierwszym projektem badawczym zmierzającym do budowy

40

Page 41: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

federacyjnej bazy danych w oparciu o relacyjną bazę danych. Najważniejsze fragmenty tego

prototypu są obecnie częścią DB2 [51].

Konfiguracja prostego systemu federacyjnego w DB2 składa się z kilku kroków. Po pierwsze,

w serwerze federacyjnej bazy danych rejestrowana jest (za pomocą operacji CREATE WRAPPER)

osłona do integrowanego zasobu. Następnie tworzony jest (za pomocą instrukcji CREATE SERVER)

obiekt bazodanowy reprezentujący zdalny serwer. W kolejnym kroku musi zostać opisana struktura

każdej zdalnej tabeli, do której odwoływać się ma serwer integracyjny (operacja CREATE

NICKNAME). Nazwy podane podczas ostatniej z tej operacji dostępne są w przezroczysty sposób dla

języka SQL. Przykładowo, istnieje możliwość zbudowania perspektywy bazodanowej (CREATE

VIEW) odwołującej się zarówno do lokalnych jak i zdalnych danych serwera federacyjnej bazy

danych. Choć na pierwszy rzut oka wydawać by się mogło że perspektywa zrealizowana w taki

sposób ukrywa przed użytkownikiem fakt rozproszenia danych, w rzeczywistości nie jest to do

końca prawdą. Podstawowy problem z transparentnością takiego rozwiązania powstaje

w momencie, gdy użytkownik SZFBD usiłuje zaktualizować dane zwrócone przez taką

perspektywę, okazuje się że w wielu przypadkach nie jest jest to możliwe, wskutek dobrze znanego

problemu aktualizacji perspektyw. W opracowaniach dotyczących DB2 poleca się zatem

zaimplementowanie aktualizacji za pomocą wyzwalaczy INSTEAD OF.

Poważnym problemem w dziedzinie federacyjnych baz danych jest optymalizacja zapytań

rozproszonych. Ze względu na bardzo duży czas dostępu do rozproszonych zasobów, potrzebna jest

specjalna strategia ewaluacji zapytań operujących na takich danych. W relacyjnych bazach danych

zwłaszcza operacja złączenia tabel wymaga specjalnego sposobu ewaluacji. Najczęściej

wykorzystuje się tutaj techniki dekompozycji zapytań na podzapytania wysyłane do różnych

serwerów, jak również półzłączenia (semi-joins) wraz z przesyłaniem między serwerami danych

potrzebnych do wykonania operacji cząstkowych.

Charakterystyczną cechą istniejące na rynku systemów zarządzania bazami danych jest to, iż oprócz

integracji danych w postaci federacji i klastrów, pozwalają również na budowę (np. w języku PL/

SQL) aplikacji pracujących po stronie serwera bazy danych. W środowisku takim procedury

składowane mogą być udostępniane jako usługi seciowe (WebServices), aplikacje mogą

komunikować się zarówno za pomocą RPC jak i kolejek, a wszystkie operacje realizowane są pod

kontrolą silnych mechanizmów dostarczanych przez SZBD do ochrony danych (np. mechanizmy

transakcji, bezpieczeństwa, dzienniki, itp.). Z punktu widzenia twórcy oprogramowania

41

Page 42: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

uruchamianego w kontekście serwera bazy danych te bardzo złożone mechanizmy są praktycznie

niewidoczne. Jest to zatem sytuacja zupełnie niż w przypadku middleware, gdzie programista

zmuszony jest korzystać ze złożonego API.

Obiektowe bazy danych dodają do tego obrazu obsługę technologii rozproszonych obiektów.

Dodanie do obiektowej, federacyjnej bazy danych silnego języka programowania, mocno

zintegrowanego z konstrukcjami deklaratywnym, oraz zmniejszenie rozmiarów samego

oprogramowania do objętości dzisiejszych maszyn wirtualnych popularnych języków

programowania stwarza możliwość wykorzystania takiej bazy danych jako narzędzia

programistycznego, które nie jest ograniczone do pracy po stronie serwera. Uzyskane w ten sposób

narzędzie posiada potencjał reprezentowania wielu różnych metod integracji danych i aplikacji

w ramach tego samego narzędzia. Wydaje się, iż mechanizmy przezroczystości oraz

wysokopoziomowy charakter pracy w środowisku takiego narzędzia powinny doprowadzić do

znaczącego zmniejszenia kosztu produkcji oprogramowania oraz jego utrzymania.

PodsumowanieW rozdziale omówiliśmy najbardziej popularne techniki łączenia aplikacji z bazami danych oraz

aplikacji rozproszonych. Krótko umówiliśmy rozwiązania podjęte przy projektowaniu takich metod

dostępu do danych jak interfejs poziomu wywołań, języki z trwałością, odwzorowanie relacyjno-

obiektowe, czy obiektowe bazy danych. Przeanalizowaliśmy również najważniejsze wady i zalety

technologii rozproszonych obiektów oraz federacyjnych baz danych. Rozdział podsumowaliśmy

stwierdzeniem, iż zastosowanie rozproszonych obiektów w kontekście rozproszonych baz danych

daje nadzieję na rozwiązanie wielu problemów inherentnych dla standardu CORBA oraz

podobnych technologii.

42

Page 43: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdział 3:Podejście stosowe do języków zapytań

WprowadzeniePodejście stosowe (Stack-Based Approach, SBA) do języków zapytań [4] jest spójną teorią

umożliwiającą stworzenie silnego języka zapytań dla praktycznie dowolnego znanego obecnie

modelu danych. Podstawą podejścia stosowego jest założenie, że języki zapytań są odmianą

języków preogramowania. Do języków zapytań powinno się zatem stosować pojęcia,

koncepcje i metody znane i skuteczne w językach programowania. Przykładowo, głównym

pojęciem semantyki i implementacji większości języków programowania jest stos środowisk. Jest

on podstawą mechanizmu określania zakresu nazw, wiązania nazw, wywoływania procedur [94]

(włączając wołania rekurencyjne), komunikowania parametrów oraz realizacji pojęć obiektowości,

takich jak hermetyzacja, dziedziczenie i polimorfizm. Istotą podejścia stosowego do języków

zapytań jest wykorzystanie mechanizmu stosu środowiskowego do definiowania i implementacji

operatorów charakterystycznych dla języków zapytań, takich jak operatory selekcji, projekcji,

nawigacji i złączenia. Dzięki semantyce opartej na pojęciu stosu środowisk, w SBA osiągnięto

pełną ortogonalność i kompozycyjność operatorów, a także możliwość bezszwowej integracji

języka zapytań z konstrukcjami imperatywnymi i innymi abstrakcjami programistycznymi

(procedury, klasy, typy, itd.). W niniejszym rozdziale przedstawimy skrótowy opis najważniejszych

pojęć charakterystycznych dla tego podejścia. Szczegółowy opis SBA dostępny jest w [4].

43

Page 44: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Modele danychPodejście stosowe jest zdefiniowane dla szeregu uniwersalnych modeli składu obiektów.

W zależności od złożoności modelu, określane są one nazwami M0, M1, M2 i M3. Każdy kolejny

model rozszerza poprzedni o nowe właściwości. Naturalnie zbiór ten nie wyczerpuje wszystkich

możliwych modeli składów, a jedynie najbardziej znane obecnie.

Model M0 jest zbudowany zgodnie z zasadami relatywizmu i wewętrznej identyfikacji obiektów.

Jest to bardzo prosty model danych, zdolny reprezentować dane półstrukturalne [93]. W modelu M0

każdy obiekt składa się z identyfikatora wewnętrznego (niedostępnego dla programisty),

identyfikatora zewnętrznego (nazwy dostępnej dla programisty), oraz wartości. Istnieją trzy rodzaje

obiektów: atomowe, referencyjne, złożone. Zakładając że I oznacza zbiór wszystkich

dopuszczalnych identyfikatorów wewnętrznych, N oznacza zbiór wszystkich dopuszczalnych nazw

zewnętrznych obiektów, V zbiór wartości prostych takich jak liczby, napisy, itd., a O zbiór

dowolnych obiektów modelu M0, wówczas możemy napisać że obiekty modelu M0 to trójki

następujących rodzajów (dla i1, i2 ∈ I, n ∈ N, oraz v ∈ V):

• Obiekty atomowe <i1, n, v>. Są to najprostsze rodzaje obiektów. Identyfikowane są jednoznacznie

za pomocą identyfikatora wewnętrznego i1, posiadają nazwę n, przechowują wartość atomową v.

• Obiekty referencyjne <i1, n, i2>. Obiekty te służą do modelowania powiązań między obiektami.

Podobnie jak w poprzednim przypadku, identyfikowane są jednoznacznie za pomocą

identyfikatora wewnętrznego i1 i posiadają nazwę n. Wartością i2 tych obiektów są identyfikatory

wewnętrzne wskazywanych obiektów.

• Obiekty złożone <i1, n, O>. Obiekty te służą do modelowania zagnieżdżania obiektów. Obiekt

o identyfikatorze i1, oraz nazwie n, składa się z obiektów należących do O. Innymi słowy

elementy O są podobiektami obiektu i1.

Przykładowo, pewna baza danych może składać się z następującego zbioru obiektów (obiekt entry

jest systemowym obiektem pełniącym rolę korzenia bazy danych):

<i0, entry, <i1, Employee, <i4, Name, “J. Smith”> <i5, Salary, 65000> > <i2, Employee, <i6, Name, “S. Bush”> <i7, Salary, 45000>

44

Page 45: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

> <i3, Department, <i8, Name, “Sales”> <i9, Location, “London”> >>

Model M1 jest rozszerzeniem M0 o klasy i dziedziczenie. Klasa jest zwykłym obiektem złożonym,

zawierającym podobiekty reprezentujące niezmienniki pewnej grupy obiektów. Między obiektami

reprezentującymi klasy można deklarować relację dziedziczenia. Oprócz relacji dziedziczenia,

występuje również relacja przynależności obiektu do klasy.

Model M2 wprowadza pojęcie dynamicznej roli obiektu. Każdy obiekt może przyjmować jedną lub

kilka takich ról. Posiadanie jakiejś roli przez obiekt przypomina sytuację gdy obiekt ten jest

instancją klasy. Podczas jednak gdy dziedziczenie ma charakter statyczny, w czasie wykonania

obiekt może zyskiwać nowe oraz tracić stare role, zaś dziedziczenie pomiędzy rolami ma charakter

dynamiczny [99].

Model M3 wprowadza mechanizm hermetyzacji. Model ten może być zarówno rozszerzeniem

modelu M1, jak i modelu M2. Przyjmuje się, że każda klasa może być wyposażona w listę

eksportową, czyli zbiór nazw pól klasy które są widoczne na zewnątrz implementującego ją

obiektu. Pozostałe nazwy nie są widoczne, i traktowane są jako prywatne.

StosyIstotą podejścia stosowego jest zastosowanie dwóch stosów do objaśnienia semantyki języka

zapytań. Istnieją dwa stosy: stos rezultatów oraz stos środowiskowy.

Pierwszy z tych stosów, czyli stos rezultatów (Query Result Stack, QRES), służy do

przechowywania tymczasowych oraz końcowych rezultatów zapytań. Oznaczmy przez R zbiór

wszystkich rezultatów zapytań, zaś przez SR ⊂ R - zbiór rezultatów zapytań nie będących

kolekcjami.

Do zbioru rezultatów zapytań R, mogą należeć następujące elementy r:

• Wartość prosta (liczba, ciąg znaków, wartość logiczna, etc.).

Wartości takie są rezultatami wyrażeń będących literałami, bądź powstają na skutek dereferencji

obiektu atomowego przechowywanego w bazie danych.

• Referencja (identyfikator wewnętrzny obiektu).

Wartości takie zwykle są rezultatami wyrażeń odwołujących się poprzez nazwę do obiektu

45

Page 46: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

przechowywanego w składzie danych (inaczej mówiąc: są rezultatami wiązania nazw). Mogą być

również rezultatami dereferencji (pobrania wartości) obiektów referencyjnych.

• Binder (para <n, r>, gdzie n ∈ N, r ∈ R).

Wartości takie powstają na skutek działania operatorów wprowadzających nazwę pomocniczą (as,

groupas), albo jako rezultat operacji nested ix, gdzie ix jest identyfikatorem obiektu

wskaźnikowego. Binder jest zapisywany w postaci n(r).

• Struktura ( struct { r1, r2, ..., rn }, r1, r2, ..., rn ∈ SR)

Jest to ciąg pojedynczych rezultatów (elementów zbioru SR, czyli zbioru R z wyjątkiem kolekcji).

Struktury najczęściej powstają dzięki operatorom przecinka (konstrukcja struktury) lub join, albo

jako rezultat operacji deref iy, gdzie iy jest identyfikatorem wewnętrznym obiektu złożonego.

• Kolekcja pojedynczych rezultatów (bag { r1, r2, ..., rn }, sequence { r1, r2, ..., rn }, r1, r2, rn ∈ SR)

Elementem kolekcji może być dowolny element zbioru R, z wyjątkiem innej kolekcji. Kolekcje

rezultatów nie mogą być elementami kolekcji, chyba że są wartościami binderów. Kolekcje

powstają najczęściej jako wynik wiązania nazw, albo jako rezultat operatorów zbiorowych (np.

union). Istnieją dwa rodzaje kolekcji: wielozbiór (bag) i sekwencja. Pierwszy nie zachowuje

kolejności elementów, a drugi zachowuje. Możliwe są także inne rodzaje kolekcji (np. tablica),

różniące się od omówionych powyżej zestawem generycznych operatorów oraz (niekiedy)

sposobem fizycznej implementacji.

Drugi z wymienionych stosów, czyli stos środowiskowy (Environment Stack, ENVS) służy do

kontrolowania zakresu nazw. Stos środowiskowy składa się z sekcji, a każda sekcja zawiera 0 lub

więcej binderów. Binder jest tworem który służy do wiązania nazwy z odpowiednim bytem czasu

wykonania. W dalszej części pracy bindery będziemy zapisywać jako n(r), gdzie n ∈ N, r ∈ R.

Operacja bindW podejściu stosowym każda nazwa występująca w zapytaniu jest wiązana z odpowiednim bytem

czasu wykonania, zgodnie z zakresem tejże nazwy. Wiązanie nazw realizowane jest przez operację

nazywaną w naszym opisie jako bind. Operacja bind działa na stosie środowiskowym, i jej

zadaniem jest odpowiednie przeszukanie sekcji tego stosu. Na początku ewaluacji zapytania stos

składa się z jednej sekcji (tzw. sekcji bazowej), w której przechowywane są bindery do wszystkich

obiektów korzeniowych. W trakcie ewaluacji zapytania na stosie pojawiają się i znikają dodatkowe

sekcje (puste lub zawierające bindery), ale sekcja bazowa zawsze na nim pozostaje.

46

Page 47: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Mechanizm wiązania nazwy n polega na przeszukiwaniu stosu środowisk w kierunku od szczytu

w dół w poszukiwaniu pierwszej takiej sekcji, która zawiera przynajmniej jeden binder

o poszukiwanej nazwie. Ponieważ nazwy binderów mogą się powtarzać w ramach danej sekcji,

dlatego operacja bind może wyszukać taką sekcję, w której znajduje się kilka binderów o wiązanej

nazwie. W takim przypadku wynikiem wiązania jest kolekcja zawierająca wartości wszystkich

znalezionych binderów. W szczególności, jeśli żadna sekcja nie zawiera bindera o nazwie n,

wówczas rezultatem wiązania jest pusta kolekcja. Alternatywnie, (szczególnie przy mocnej kontroli

typologicznej) brak odpowiedniego bindera sygnalizowany jest jako błąd typologiczny.

Operacja nestedOperacja nested służy do wyznaczania wnętrza nowej sekcji, która umieszczana jest na stosie

środowiskowym. Operacja pobiera jako argument dowolny rezultat zapytania, natomiast zwraca

zbiór binderów. W zależności od rodzaju argumentu, mogą pojawić się następujące sytuacje:

• Jeśli argumentem jest referencja do obiektu złożonego, wówczas rezultatem operacji nested jest

zbiór składający się z binderów utworzonych na podstawie podobiektów tego obiektu złożonego.

Dla każdego podobiektu tworzony jest binder o takiej nazwie jak ten podobiekt, oraz wartości

będącej identyfikatorem wewnętrznym tego podobiektu.

• Jeśli argumentem jest referencja do obiektu wskaźnikowego, wówczas rezultatem operacji nested

jest zbiór zawierający binder o nazwie takiej, jak nazwa docelowego obiektu wskazywanego

przez ten obiekt wskaźnikowy, oraz wartości będącej identyfikatorem wewnętrznym tego

wskazywanego obiektu.

• Jeśli argumentem jest binder, wówczas rezultatem jest zbiór zawierający binder o takiej samej

nazwie i wartości jak binder wejściowy.

• Jeśli argumentem jest strukturą, wówczas rezultatem operacji nested jest zbiór będący sumą

mnogościową rezultatów funkcji nested wykonanych dla każdego pola tej struktury.

• Dla pozostałych argumentów rezultatem operacji jest zbiór pusty.

Wyrażenia i ich ewaluacjaPodejście stosowe traktuje zapytania w taki sam sposób, jak tradycyjne języki programowania

traktują wyrażenia. Terminu wyrażenie można zatem używać zamiennie z terminem zapytanie.

Pomimo, iż SBA jest niezależne od składni, do objaśnienia niektórych konstrukcji semantycznych

używa się składni abstrakcyjnej noszącej nazwę SBQL (Stack-Based Query Language).

47

Page 48: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Podstawową cechą SBQL jako składni jest dążenie do unikania lukru składniowego,

w szczególności charakterystycznej dla SQL konstrukcji select..from..where.

Wyrażenia SBQL posiada własność kompozycyjności. Podobnie jak w językach programowania,

najprostszymi zapytaniami są nazwy i literały. Bardziej złożone zapytania uzyskuje się poprzez

łączenie podzapytań za pomocą operatorów. W ten sposób każde zapytanie składa się z szeregu

podzapytań. Nie istnieją żadne ograniczenia dotyczące zagnieżdżania zapytań.

SBA posługuje się semantyką operacyjną do zdefiniowania operatorów mogących być częścią

zapytania. Poniżej prezentujemy listę najważniejszych operatorów oraz opis ich semantyki:

• +, - — tradycyjne, unarne operatory arytmetyczne.

Ewaluacja: 1. Wykonaj podzapytanie. 2. Podnieś element ze stosu QRES. 3. Sprawdź czy jest to

po jedynczy element. Jeśli nie, podnieś wyjątek czasu wykonania. 4. Jeśli wynik jest referencją,

wykonaj dereferencję. 5. Sprawdź typ rezultatu. Jeśli operator nie może być zastosowany dla

takiej wartości, podnieś błąd czasu wykonania. 6. Wykonaj operację związana z danym

operatorem. 7. Umieść rezultat na QRES.

• – +, -, *, /, =, <>, <, >, <=, >=, or, and — tradycyjne binarne operatory arytmetyczne,

logiczne i porównania. Ewaluacja: 1. Wykonaj oba podzapytania. 2. Podnieś dwa elementy

z QRES. 3. Sprawdź czy są to pojedyncze wartości. Jeśli nie, podnieś błąd czasu wykonania.

4. Jeśli którykolwiek z rezultatów jest referencją, wykonaj dereferencję. 5. Sprawdź typy danych

obu rezultatów. Jeśli operator nie może być zastosowany do takich wartości, podnieś błąd czasu

wykonania. 6. Wykonaj operację związaną z operatorem. 7. Umieść rezultat na QRES.

• – , (przecinek) — iloczyn kartezjanski (uogólniony dla bagów).

Ewaluacja: 1. Zainicjalizuj pusty bag (będziemy odnosić się do niego jako eres ). 2. Wykonaj oba

podwyrażenia. 3 Podnieś jeden element z QRES (będziemy odnosić się do niego jako e2res ).

4. Podnieś jeden element z QRES (będziemy odnosić się do niego jako e1res ). 5. Dla każdego

elementu e1 z e1res wykonaj: 5.1 Dla każdego elementu e2 z e2res wykonaj: 5.1.1 utwórz struct

{ e1, e2 }. Jeśli e1 i/lub e2 jest strukturą, weź jej pola. 5.1.2 Dodaj strukturę do eres. 6. Umieść

eres na QRES.

• bag, sequence — konstruktory bagów i sekwencji. Ewaluacja: 1. Zainiacjalizuj pusty bag

(będziemy odnosić się do niego jako eres ). 2. Wykonaj podzapytanie. 3. Podnieś wynik z QRES.

4. Potraktuj go jako strukturę. Każde pole tej struktury dodaj do eres. 5. Umieść eres na QRES.

48

Page 49: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• union — suma zbiorów (uogólniony dla bagów).

Ewaluacja: 1. Zainicjalizuj pusty bag (będziemy odnosić się do niego jaki eres). 2. Wykonaj oba

podwyrażenia. 3. Podnieś dwa elementy z QRES. 4. Dodaj wszystkie elementy z obu rezultatów

do eres. 5. Umieść eres na QRES.

• minus, intersect, in — tradycyjne operatory zbiorowe (uogólnione dla bagów).

Ewaluacja: podobnie jak w union. W celu porównania wartości operator może dokonywać

dereferencji rezultatów.

• sum — suma elementów kolekcji.

Ewaluacja: 1. Zainicjalizuj wartość, która będzie służyć do przechowywania sumy (będziemy

odnosić się do niej jako eres ). 2. Wykonaj podzapytanie. 3. Podnieś jeden element z QRES. 4.

Dla każdego elementu e wykonaj: 4.1 Jeśli rezultat jest referencją, wykonaj dereferencję. 4.2 Jeśli

rezultat (po ewentualnej dereferencji) nie jest liczbą, podnieś błąd czasu wykonania. 4.3 Dodaj

liczbę do eres. 5. Umieść eres na QRES.

• min, max, unique, exists, count — tradycyjne operatory agregujące.

Ewaluacja: podobnie jak sum. Ostatnie dwa operatory nie dokonują dereferencji rezultatów.

• . (kropka) — projekcja/nawigacja (niealgebraiczny).

Ewaluacja: 1. Zainicjalizuj pusty bag (będziemy się do niego odnosić jako eres). 2. Wykonaj lewe

podzapytanie. 3. Podnieś jego rezultat ze stosu QRES. 4. Dla każdego elementu e z rezultatu

otrzymanego w poprzednim kroku wykonaj: 4.1. Otwórz nową sekcję na ENVS. 4.2. Wykonaj

operację nested(e). 4.3. Wykonaj prawe podzapytanie. 4.4 Podnieś jego rezultat z QRES. 4.5.

Dodaj go do eres. 5. Połóż eres na QRES.

• where — selekcja (niealgebraiczny).

Ewaluacja: podobnie jak w . (kropka). 4.5. Jeśli wynik ewaluacji prawego wyrażenia nie jest

pojedynczą wartością logiczną, podnieś błąd czasu wykonania. 4.6. Jeśli rezultatem prawego

podzapytania jest true, dodaj ten wynik do eres.

• join — złączenie zależne (niealgebraiczny).

Ewaluacja: podobnie jak w . (kropka). 4.5. Zamiast dodawania rezultatu do eres, wykonaj iloczyn

kartezjański e z rezultatem wykonania prawego podzapytania. 4.6. Dodaj otrzymaną strukturę do

eres. 5. Połóż eres na QRES.

49

Page 50: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• forall — kwantyfikator ogólny (niealgebraiczny).

Ewaluacja: podobnie jak w . (kropka). 4.5. Jeśli rezultat prawego wyrażenia nie jest pojedynczą

wartością logiczną, podnieś błąd czasu wykonania. 4.6. Jeśli rezultat prawego wyrażenia jest

false, umieść wartość false na QRES i przerwij ewaluację operatora.

• forany — kwantyfikator szczegółowy (niealgebraiczny).

Ewaluacja: podobnie jak w . (kropka). 4.5. Jeśli rezultatem prawego wyrażenia nie jest

pojedyncza wartość logiczna, zgłoś błąd czasu wykonania. 4.6. Jeśli rezultatem prawego

wyrażenia jest true, umieść true na QRES i przerwij ewaluację operatora.

• orderby — sortowanie (niealgebraiczny).

Ewaluacja: 1. Wykonaj operację join. 2. Podnieś wynik z QRES. 3. Posortuj otrzymane struktury

wg drugiego pola każdej z tych struktur, później trzeciego, czwartego, etc. 3. Usuń wszystkie

z wyjątkiem pierwszego pola otrzymanych struktur. 4. Odłóż kolekcję struktur na QRES.

• as — przypisanie nazwy pomocniczej elementom kolekcji.

Ewaluacja: 1. Wykonaj podzapytanie. 2. Podnieś rezultat z QRES. 3. Każdy element otrzymanej

kolekcji zastąp binderem o nazwie podanej jako parametr operatora i wartości będącej

zastępowanym rezultatem. 4. Umieść wynikowa kolekcje na QRES.

• groupas — przypisanie nazwy pomocniczej całemu rezultatowi.

Ewaluacja: 1. Wykonaj podzapytanie. 2. Podnieś jego rezultat z QRES. 3. Utwórz binder o nazwie

podanej jako parametr operatora oraz wartości otrzymanej w poprzednim kroku. 4. Połóż go na

QRES.

• :< — przeniesienie obiektu w nowe miejsce (imperatywny).

Ewaluacja: 1. Wykonaj prawe podzapytanie. 2. Podnieś jego rezultat z QRES (będziemy nazywać

go dalej res). 3. Jeśli rezultat ten nie jest po jedynczym binderem, zgłoś błąd czasu wykonania.

4. Wykonaj lewe podzapytanie. 6. Podnieś rezultat z QRES (będziemy nazywać go dalej ref ).

6. Jeśli rezultat ten nie jest pojedynczą referencją, zgłoś błąd czasu wykonania. 7. Utwórz w bazie

danych nowy obiekt i podłącz go pod ref. Rodzaj tego obiektu powinien odzwierciedlać poziom

zagnieżdżenia binderów w res. Jeśli wartoscią bindera res jest wartość prosta, wówczas będzie to

obiekt prosty. Jeśli będzie to binder lub struktura res, wówczas utworzony powinien być obiekt

złożony (być może z kolejnymi podobiektami, jeśli bindery są zagnieżdżone, lub ich wartości są

strukturami), itd.

50

Page 51: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• update — modyfikacja wartości (imperatywny).

Ewaluacja: 1. Wykonaj podzapytanie. 2. Podnieś jego rezultat z QRES. 3. Dla każdego elementu

z otrzymanej kolekcji wykonaj: 3.1. Jeśli element ten nie jest strukturą o dwóch polach, w której

pierwsze pole jest referencją, zgłoś błąd czasu wykonania. 3.2. Jeśli typ obiektu bazy danych

o referencji w pierwszym polu tej struktury posiada typ niezgodny z typem drugiego pola tej

struktury, zgłoś błąd czasu wykonania. 3.3. Zmodyfikuj obiekt w bazie danych o referencji

w pierwszym polu analizowanej struktury, nadając mu wartość drugiego pola struktury.

• delete — usunięcie obiektów (imperatywny).

Ewaluacja: 1. Wykonaj podzapytanie. 2. Podnieś jego rezultat z QRES. 3. Dla każdego elementu

z kolekcji otrzymanej w poprzednim punkcie wykonaj: 3.1. Sprawdź czy rezultat jest referencją.

3.2. Jeśli nie, podnieś błąd czasu wykonania. 3.3. Jeśli tak, usuń z bazy danych obiekt o podanym

identyfikatorze. 3.4. Włóż pustego baga na QRES.

Metabaza i statyczna analiza zapytańPodczas kompilacji zapytania SBQL mogą zostać poddane analizie statycznej. Analiza statyczna

niezbędna jest do zrealizowania statycznej kontroli typów oraz niektórych operacji

optymalizacyjnych. Mechanizm ten polega na wstępnym wykonaniu zapytania, realizowanym

podczas kompilacji, a nie w czasie wykonania. Zadaniem takiej ewaluacji jest zasymulowanie

możliwie największej liczby sytuacji zachodzących podczas czasu wykonania, ale za pomocą

danych dostępnych podczas kompilacji. Zapytanie wykonywane jest nie na rzeczywistych

obiektach bazy danych, ale na tzw. metabazie. Metabaza jest grafem schematu bazy danych,

skonstruowanym na podstawie deklaracji bytów programistych. Graf schematu bazy danych jest

strukturą podobną do grafu bazy danych, i rownież jest modelowany za pomoca obiektów prostych,

złożonych i referencyjnych. Podstawowa różnicą w stosunku do grafu bazy danych jest to, iż:

1. w metabazie zamiast konkretnych wystąpień obiektów przechowywane są informacje

o minimalnej i maksymalnej dopuszczalnej ich ilości (tzw. liczność).

2. zamiast wartości przechowywane są informacje o typach danych i relacjach (np. dziedziczenia)

między nimi.

3. metabaza może również zawierać dodatkowe informacje na temat danych przechowywanych

w bazie danych, np. statystyki potrzebne przy optymalizacji kosztowej.

Przykładowo, dla następującego fragmentu kodu źródłowego:

51

Page 52: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

x : integer [1..5];y : record { a : string; b : string; }

metabaza (zapisana zgodnie z modelem M0) może wyglądać następująco:

<i0, entry, <i1, x, <i2, meta_object_kind, META_VARIABLE> <i3, type_kind, PRIMITIVE> <i4, type, INTEGER> <i5, min_card, 1> <i6, max_card, 5> > <i7, y, <i8, meta_object_kind, META_VARIABLE> <i9, type_kind, COMPLEX> <i10, type, i13> <i11, min_card, 1> <i12, max_card, 1> > <i13, $x_struct_type, <i14, meta_object_kind, META_STRUCTURE> <i15, fields, <i16, x, <i17, meta_object_kind, META_VARIABLE> <i18, type_kind, PRIMITIVE> <i19, type, STRING> <i20, min_card, 1> <i21, max_card, 1> > <i22, x, <i23, meta_object_kind, META_VARIABLE> <i24, type_kind, PRIMITIVE> <i25, type, STRING> <i26, min_card, 1> <i27, max_card, 1> > > >>

Odpowiednikiem rezultatu zapytania podczas analizy statycznej, jest sygnatura operacji. Istnieją

następujące rodzaje sygnatur: statyczna referencja, statyczny binder, wariant, reprezentacja typu

wartości, statyczna struktura. Sygnatura reprezentująca statyczną referencję zawiera referencję do

pewnego obiektu metabazy. Statyczny binder zawiera nazwę oraz związaną z nim sygnaturę będącą

wartością bindera. Wariant zawiera kilka możliwych sygnatur, jeśli w czasie kontroli typów nie

można jednoznacznie wyznaczyć jednej sygnatury. Sygnatura reprezentująca wartość zawiera

identyfikator typu prostego jaki reprezentuje (dotyczy zwykle literałów oraz statycznych referencji

52

Page 53: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

obiektów prostych poddanych dereferencji). Sygnatura reprezentująca strukturę zawiera zbiór

sygnatur reprezentujących pola tej struktury. Każda z tych sygnatur może również przechowywać

pewne dodatkowe informacje, np. liczności. Liczności pozwalają określić przybliżoną liczbę

rezultatów zwracanych przez operację reprezentowaną przez daną sygnaturę.

Oprócz sygnatur, analizator kontekstowy zapytań wyposażony jest również w statyczne

odpowiedniki stosu środowiskowego i stosu rezultatów zapytań. W odróżnieniu od ich

odpowiednikow z czasu wykonania, struktury te działaja na sygnaturach oraz grafie schematu bazy

danych, a nie na rezultatach zapytań.

Kontrola typówAnaliza zapytań podczas kompilacji pozwala m.in. na zrealizowanie operacji statycznej kontroli

typologicznej [9]. Na podstawie reguł wnioskowania o typach zaprojektowanych dla każdego

operatora, kompilator jest w stanie wywnioskować typ wartości zwracany przez złożone zapytanie,

analizując jego poszczególne części. Przykładowo, pojedyncza reguła dla operatora union może

wyglądąć następująco:

bag [a..b] (typ) union bag [c..d] (typ) ⇒ bag [a + c, b + d] (typ)

Reguła ta mówi, iż sumując zbiór A, w którym może być od a do b wartości oraz zbiór B, mogący

potencjalnie składać się z od c do d wartości, w wynikowym zbiorze nigdy nie znajdzie się mniej

rezultatów niż a + c, oraz więcej niż b + d.

Zbiór podobnych reguł jest częścią wewnętrznego systemu typów każdego języka programowania.

Ponieważ jednak SBQL jest językiem zapytań, dlatego jego sygnatury operacji wzbogacone są

o informacje dotyczące kolekcji: liczności i uporządkowanie.

Reguły dla operatorów arytmetycznych zwykle są bardziej restrykcyjne. Przykładowo, dla

operatora + można zaprojektować następującą regułę wnioskowania:

wartość [1..1] (integer) + wartość [1..1] (real) ⇒ wartość [1..1] (real)

Reguła przedstawiona powyżej zakłada, że operację dodawania na wartościach integer i real

można wykonać tylko wtedy, gdy lewy i prawy argument posiadają liczność [1..1] (czyli

odpowiednie wartości zawsze występuja w bazie danych), w przeciwnym razie następuje błąd

typologiczny. Można się zastanawiać, czy założenie dotyczące liczności w powyższym przykładzie

nie jest zbyt restrykcyjne i czy w związku z tym część kontroli typologicznej nie powinna zostać

53

Page 54: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

przeniesiona do czasu wykonania. Alternatywna postać powyższej reguły może zatem również

przyjąć następującą postać:

wartość [0..*] (integer) + wartość [0..*] (real) ⇒ wartość [1..1] (real)

W tym przypadku operator + dopuszcza sytuację w której w czasie kompilacji nieznana jest

liczność jego argumentów. Właściwa kontrola następuje podczas czasu wykonania. W takiej

sytuacji jeśli lewe lub prawe podzapytanie nie zwróci pojedynczej wartości, interpreter zgłasza błąd

czasu wykonania. Takie założenie prowadzi do systemu typów, który możemy określić jako

półmocny (semi-strong).

Poniżej przedstawiono przykładowe zapytanie ilustrujące przyczynę dla której półmocny system

typów jest wygodniejszy dla programisty, niż bardzo restrykcyjny:

(employee where name = “Smith”).salary + 500

W przykładzie tym wykorzystuje się założenie, że istnieje dokładnie jeden pracownik o nazwisku

Smith. To założenie jest kontrolowane dynamicznie. Jeżeli nie jest spełnione, wówczas w czasie

wykonania sygnalizuje się błąd typu. W przypadku restrykcyjnego systemu typów, powyższa

konstrukcja musiałaby zostać odrzucona przez kompilator.

Optymalizacja zapytańDrugim kluczowym zastosowaniem analizy statycznej jest optymalizacja zapytań przez

przepisywanie [7]. Metoda ta polega na wykorzystaniu informacji dotyczącej wysokości stosu

środowiskowego podczas ewaluacji różnych części zapytania. Dzięki temu, podczas analizy

zapytania każdemu operatorowi niealgebraicznemu można przypisać liczbę oznaczającą numer

otwieranej przez niego sekcji, zaś każdej z nazw można przypisać wysokość stosu (liczba sekcji na

ENVS) w chwili, gdy dana nazwa jest wiązana, oraz numer sekcji, w której ta nazwa jest wiązana.

Jeśli wszystkie nazwy danego podzapytania wiązane są w sekcji innej niż ta, która na stos kładzie

aktualnie ewaluowany operator niealgebraiczny, to może ono być obliczone zanim ten operator

otworzy swoją sekcje, czyli wcześniej, niż to wynika z tekstowego umieszczenia tego podzapytania

w zapytaniu. Ma to duże znaczenie dla optymalizacji operatorów niealgebraicznych, ponieważ

pozwala uniknąć sytuacji w których dane podzapytanie liczone jest wielokrotnie, pomimo że

zawsze zwraca ten sam wynik. Przykładowo, wykorzystując tę metodę optymalizator może

przekształcić następujące zapytanie:

employee where salary = (employee where name = "Smith").salary;

54

Page 55: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

do następującej postaci:

((employee where name = "Smith").salary groupas x).(employee where salary = x);

Dzięki temu przekształceniu podzapytanie wyznaczające zarobek Smitha wyliczane jest tylko raz,

na samym początku (później jego wynik jest wielokrotnie wykorzystywany), zamiast dla każdego

pracownika osobno.

Innym rodzajem optymalizacji, jaki może zostać zastosowany podczas analizy statycznej, jest

wykorzystanie rozdzielności operatorów. Operator niealgebraczny ∆ jest rozdzielny względem

operatora union, jeżeli dla dowolnego stanu składu bazy danych, stanu ENVS oraz zapytań q1, q2,

q3 zapytanie

(q1 union q2) ∆ q3

jest semantycznie równoważne zapytaniu:

(q1 ∆ q3) union (q2 ∆ q3)

Równoważnie, operator ∆ jest rozdzielnywzględem union, jeżeli dla dowolnego zapytania o postaci

q1 ∆ q2, gdzie q1 zwraca bag{r1, r2, ..., rk}, końcowy rezultat może być wyznaczony jako

(r1 ∆ q2) union (r2 ∆ q2) union ... union (rk ∆ q2)

Dzięki właśności rozdzielności operatorów możliwe są dodatkowe przekształcenia, np. znane

z systemów relacyjnych przesunięcie selekcji przed złączenie:

(q1 join q2) where q3 ⇒ q1 join (q2 where q3)

Oprócz przedstawionych wyżej dwóch mechanizmów, SBQL może być również optymalizowany

z użyciem takich struktur jak indeksy, czy takich metod, jak usuwanie niepotrzebnych nazw

pomocniczych, martwych podzapytań, optymalizacja kosztowa, i in. Metody te opisane są

szczegółowo w pracy [7].

Aktualizowalne perspektywyPerspektywa jest wirtualnym obrazem danych zapisanych w bazie danych. Definicja perspektywy

przechowywana jest w komputerze w postaci definicji, natomiast definiowane przez nie wirtualne

dane istnieją wyłącznie w wyobraźni użytkownika lub programisty. Użytkownik formułujący

zapytanie nie potrzebuje rozróżniać, czy ma do czynienia z zapamiętaną czy też z wirtualną daną

(przezroczystość).

55

Page 56: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Do ważniejszych zastosowań perspektyw należą: możliwość przystosowania zawartości bazy

danych do potrzeb użytkownika, wspomaganie mechanizmów bezpieczeństwa, ewolucji schematu,

integracji schematów i heterogenicznych zasobów, etc.

Perspektywy w SBQL są w pełni aktualizowalne [53]. Oznacza to, że obiekty wirtualne mogą być

nie tylko odczytywane, ale również tworzone, usuwane i modyfikowane. Ta cecha odróżnia

perspektywy SBQL od perspektyw występujacych w relacyjnych bazach danych, które mogą być

aktualizowane tylko wtedy, gdy spełnione zostaną pewne warunki związane z budową zapytania.

Przykład instrukcji definiującej perspektywę relacyjną, która nie może zostać poddana działaniu

operacji aktualizacyjnych:

create view aggsalv as select avg(salary) from emp

Istotą podejścia do aktualizowalnych wirtualnych perspektyw w SBQL jest mechanizm

przeciążania generycznych operatorów imperatywnych (wiązanie nazwy, dereferencja, wstawianie,

usuwanie, aktualizowanie) stosowanych do wirtualnych obiektów. Przeciążanie następuje przez

programistę, który samodzielnie definiuje operacje jakie mają zostać wykonane zamiast domyślnej

operacji imperatywnej. Jeśli system wykrywa, iż operuje na wirtualnym obiekcie, wówczas nie

wykonuje domyślnych operacji, jakie związane są z obiektami rzeczywistymi. Zamiast tego

automatycznie wywoływane są odpowiednie procedury przeciążające umieszczone wewnątrz

definicji perspektywy przez programistę.

Drugim istotnym elementem perspektyw w SBQL jest pojęcie ziarna i związany z nim identyfikator

obiektu wirtualnego. Ziarno jest to element należący do kolekcji rezultatów zapytania definiującego

perspektywę. Ziarno służy do tworzenia wirtualnych obiektów i jest częścią wirtualnego

identyfikatora. Liczba wirtualnych obiektów generowanych przez perspektywę jest równa liczbie

rezultatów zwracanych przez zapytanie wyznaczające ziarna danej perspektywy.

Ziarna zazwyczaj są binderami, ponieważ procedury przeciążające generyczne operacje

perspektywy muszą się do tych ziaren odwoływać.

Wirtualny identyfikator jest odpowiednikiem rzeczywistego identyfikatora obiektów i przyjmuje

nastepująca formę:

<jestem wirtualny,

<OID perspektywy1, ziarno1>,

<OID perspektywy2, ziarno2>,

56

Page 57: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

...

<OID perspektywyn, ziarnon>>

Flaga jestem wirtualny pozwala odrożnić identyfikatory wirtualne od identyfikatorów

zapamiętanych obiektów. Wartości ziarno1, ziarno2, ziarnon wyznaczają w sposób jednoznaczny

obiekt wirtualny. Na podstawie wartości OID perspektywy1, OID perspektywy2, OID perspektywyn,

wiadomo z której perspektywy pochodzi wirtualny obiekt posiadający dany identyfikator. Ponieważ

perspektywy mogą być zagnieżdżone, dlatego częścią wirtualnego identyfikatora muszą być

ziarna i identyfikatory wszystkich nadperspektyw perspektywy, która generuje dany obiekt

wirtualny. Dzięki wirtualnym identyfikatorom każdy obiekt wirtualny może być jednoznacznie

identyfikowany, a w razie potrzeby system jest w stanie znaleźć perspektywę zawierającą definicję

operacji przeciążającej odpowiednią dla danego obiektu wirtualnego.

Poniższa perspektywa (nazwana PracSzef) dla wszystkich pracowników zwraca nazwisko

pracownika NazwPrac i nazwisko szefa NazwSzefa jako ciągi znaków. Podstawienie ciągu znaków

na nazwisko szefa powoduje przeniesienie pracownika do działu, którego szef ma takie nazwisko,

jak to nazwisko, które zostało użyte w podstawieniu. Nie rozpatrujemy błędnego nazwiska szefa.

Usunięcie obiektu wirtualnego powoduje usunięcie odpowiedniego rzeczywistego obiektu

pracownika.

Składnia poniższej definicji perspektywy charakterystyczna jest dla naszego prototypu.

view PracSzefDef { virtual objects PracSzef : p(ref Prac) [0..*] { return Prac as p; }

on delete { delete p; }

view NazwPracDef { virtual objects NazwPrac : np(ref string) { return p.Nazwisko as np; } on retrieve : string { return np; } }

view NazwSzefaDept { virtual objects NazwSzefa : ns(ref string) { return p.PracujeW.Dzial.Szef.Prac.Nazwisko as ns; }

on retrieve : string { return ns; }

on update NowySzef : Prac { p.PracujeW := ref Dzial where (Szef.Prac.Nazwisko) = NowySzef; } }}

57

Page 58: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Perspektywa zwraca tyle ziaren, ilu jest pracowników (zapytanie Prac as p). Każde ziarno ma postać

bindera p(iprac), gdzie p(iprac) jest referencją do obiektu Prac. Dla tej perspektywy jest zdefiniowana

tylko operacja usuwania, która w reakcji na usunięcie wirtualnego obiektu PracSzef kasuje

odpowiedni rzeczywisty obiekt Prac. Perspektywa ma dwie podperspektywy:

NazwPracDef i NazwSzefaDef.

Dla NazwPracDef zdefiniowano tylko dereferencję, która zwraca nazwisko pracownika jako ciąg

znaków. Podobnie dla NazwSzefaDef, ale dla tej podperspektywy zdefiniowano także operator

podstawiania. Powoduje on podstawienie na PracujeW referencji do działu posiadającego szefa

z nazwiskiem znajdującym się po prawej stronie podstawienia na nazwisko szefa.

Przykładem wykorzystania tej perspektywy może być następujące zapytanie:

(PracSzef where NazwPrac = “Kowalski”).NazwSzefa := “Nowak”;

W efekcie pracownik którego dotyczy to podstawienie zostanie przeniesiony do działu kierowanego

przez osobę o nazwisku podanym po prawej stronie operatora podstawiania.

PodsumowanieW rozdziale skrótowo omówiliśmy podejście stosowe do języków zapytań oraz prototypowy język

zapytań SBQL. Przedstawiliśmy podstawowe mechanizmy tego podejścia: stos środowiskowy

(ENVS), stos rezultatów zapytań (QRES), operatory niealgebraiczne, bindery. Wspomnieliśmy

również o podstawowych metodach optymalizacyjnych, statycznej kontroli zapytań,

aktualizowalnych perspektywach.

58

Page 59: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdział 4:Koncepcja architektury narzędzia RAD nowej generacji

WprowadzenieJak wspomnieliśmy w pierwszym rozdziale niniejszej pracy, walka ze złożonością oprogramowania

wymaga przede wszystkim sięgnięcia do źródeł tej złożoności, czyli sposobu postrzegania

problemów przez człowieka oraz implementacji tych problemów za pomocą maszyny. Im mniejsze

są różnice, tym prostsze jest tworzenie systemów informatycznych oraz tym mniejszy jest koszt ich

wytworzenia i pielęgnacji. Celem technik wspomagających tworzenie aplikacji powinno być zatem

zniwelowanie tych różnic poprzez zwiększenie stopnia abstrakcji na jakim pracują programiści.

Takie podejście przyświecało chociażby twórcom asemblera, języków programowania wysokiego

poziomu, pierwszych systemów zarządzania bazami danych, middleware, jak również obiektowych

metod wytwarzania oprogramowania.

Architektura narzędzia (stworzonego w ramach projektu Odra - Object Database for Rapid

Application development) prezentowanego w niniejszej pracy opiera się na następujących

założeniach:

1. Tradycyjne języki programowania nie spełniają dobrze swojej roli jako narzędzia

programowania baz danych. Podstawowym ograniczeniem tych języków jest brak pojęcia

59

Page 60: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

kolekcji jako rodzaju rezultatu wyrażenia. Konsekwencją jest brak możliwości wprowadzenia

do języka programowania operacji makroskopowych, niezbędnych do przetwarzania dużych

zbiorów danych. Potrzebna jest zatem nowa klasa języków programowania wyposażonych w tę

własność oraz pozbawionych w ten sposób negatywnego efektu niezgodności impedancji.

Zintegrowanie konstrukcji deklaratywnych z konstrukcjami imperatywnymi w ramach tego

samego języka pozwala również na zapewnienie mechanizmu statycznej kontroli typologicznej.

Cecha ta jest krytycznym elementem niemal każdego liczącego się języka programowania i jest

praktycznie nieznana w istniejących językach zapytań ze względu na ich ograniczenia

w integracji z językami programowania. Podejście stosowe do języków zapytań idealnie

wpisuje się w nasze wymagania.

2. Pożądaną cechą języka programowania aplikacji baz danych jest ortogonalna trwałość, czyli

umożliwienie operowania na danych trwałych i nietrwałych za pomocą dokładnie tych samych

środków językowych. Ortogonalna trwałość przydatna jest nie tylko po stronie serwera bazy

danych, ale również po stronie klienta.

Język z ortogonalną trwałością jest mało użyteczny jeśli w tym samym czasie tylko jedna sesja

może korzystać z przechowywanych danych. Implikuje to konieczność wprowadzenia

mechanizmów współbieżności znanych z baz danych, jak również modułu odpowiedzialnego za

przetwarzanie transakcji. Do poprawnego funkcjonowania operacji na danych masowych

niezbędny jest natomiast zestaw silnych metod optymalizacji zapytań, m.in. opartych na

indeksach. Techniki optymalizacyjne języków zapytań zazwyczaj realizowane są w czasie

wykonania, różnią się więc znacząco od typowych języków programowania (optymalizowanych

w czasie kompilacji).

Wymagania te utwierdzają nas w przekonaniu o tym, że środowiskiem uruchomieniowym

(odpowiednikiem wirtualnej maszyny Java) języka programowania o przedstawionych wyżej

cechach powinien być pełnoprawny system zarządzania obiektową bazą danych. Takie

założenie pozwala nie tylko zapewnić mechanizmy niezbędne do funkcjonowania trwałości,

ale również na wprowadzenie do języka programowania koncepcji typowo bazodanowych,

jak perspektywy czy wyzwalacze. Konstrukcje takie praktycznie nie są znane w istniejących

językach programowania. Otwierają również zupełnie nowe możliwości w dziedzinie

programowania aplikacji baz danych.

60

Page 61: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

3. W językach programowania ogólnego przeznaczenia komunikacja rozproszona realizowana jest

na bardzo niskim poziomie, poprzez API do jakiegoś middleware. Czasem (np. w przypadku

rozwiązań zgodnych ze standardem CORBA) programowanie aplikacji rozproszonych bywa

zadaniem niezwykle niewygodnym, a stworzenie stabilnie i wydajnie działającego

oprogramowania bardzo utrudnione. Bazy danych oferują tutaj znacznie bardziej

wysokopoziomowe abstrakcje, niż tylko API. Przykładowym mechanizmem komunikacyjnym

dostarczanym przez te systemy są połączenia bazodanowe (database links). Są to obiekty bazy

danych reprezentujące połączenia ze zdalnymi bazami danych. Dzięki nim wszystkie zasoby

systemu rozproszonego widziane są tak, jak gdyby przechowywane były w jednym

repozytorium. Poprzez poprzedzenie nazwy zdalnego obiektu za pomocą nazwy połączenia,

programista jest w stanie operować na zdalnych zasobach (danych, procedurach, itp.) w sposób

całkowicie przezroczysty, nawet jeśli w zapytaniu występują odwołania do kilku odrębnych

źródeł danych. Oczywiście takie podejście wymaga mechanizmu optymalizacyjnego

minimalizującego ilość danych przesyłanych przez sieć. Optymalizator taki musi być zdolny do

rozbicia głównego zapytania na podzapytania, które następnie mogą zostać rozesłane do

poszczególnych serwerów, a następnie do odpowiedniego scalenia przychodzących rezultatów.

Uważamy że dzięki automatycznej optymalizacji operacji działających na rozproszonych

danych masowych zapewniona może być znacznie większa wydajność takich operacji, niż

gdyby były oprogramowywane za pomocą tradycyjnych metod dostępnych dla tradycyjnych

middleware.

4. W celu integracji ze spadkowymi źródłami danych lub aplikacjami, system może zostać

wyposażony w szereg dodatków, takich jak zestaw filtrów, osłon oraz bram. Filtry (np. filtr dla

XML) odpowiedzialne są za importowanie danych do bazy danych Odra. Osłony (np. osłona dla

systemu Oracle) udostępniają mechanizmy pozwalające na korzystanie z zewnętrznych źródeł

danych bez importowania ich do bazy danych Odra. Bramy (np. brama dla WebServices,

sterownik JDBC) umożliwiają korzystanie z bazy danych Odra z poziomu innej technologii/

języka programowania. Oprócz tego, dla systemu Odra przygotowywany jest również

niskopoziomowy mechanizm komunikacyjny umożliwiający wywoływanie dowolnego kodu

języka Java (pozwala to m.in. na wprowadzenie do systemu możliwości korzystania z GUI).

Elementy te jednak przygotowywane są w ramach odrębnych podprojektów projektu Odra i nie

są przedmiotem opisu w niniejszej pracy. Zadaniem rozprawy jest natomiast udokumentowanie

61

Page 62: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

decyzji podjętych podczas projektowania architektury oraz implementacji jądra takiego

narzędzia.

Scenariusze zastosowaniaSystem Odra zaprojektowany jest w taki sposób, aby pełnić mógł wiele różnych ról. W najprostszej

sytuacji system oraz zintegrowany z nim język programowania/zapytań może być odpowiednikiem

popularnych języków skryptowych (np. Python, Ruby). Korzystając z podstawowych usług

(trwałość, optymalizacja, język zapytań, transakcje, itp.) zbudować jednak można za jego pomocą

znacznie bardziej rozbudowane narzędzia. Przykładowo, poniższy rysunek reprezentuje

architekturę narzędzia integracyjnego, jakie budowane jest na bazie systemu Odra na potrzeby

europejskiego projektu eGovBus.

Communication Bus

Contributory View Contributory View Contributory View

Odra

DatabaseOdra

Database

Odra

Database

Odra

Database

Integration View

Odra

Database

Odra

Database

Oracle

Wrapper

CORBA

Wrapper

Web Services

Wrapper

SBQL

Application

JMS

Wrapper

Relational

Database

CORBA

Application

Java

Application .NET Application

Contributory View

Odra

Database

Odra

Database

XML

Database

SBQL Client

Application

CORBA Client

Application

.NET Client

Application

Tamino

Wrapper

Web Services

GatewayCORBA Gateway

Java Client

Application

JDBC Gateway

Rys. 1: Docelowa architektura wirtualnego repozytorium opartego o system Odra

Systemy baz danych oparte na Odra mogą pracować w architekturze scentralizowanej,

jak i rozproszonej. W tym drugim przypadku nie zakładamy odgórnie jakiejś konkretnej

konfiguracji (np. architektura trójwarstwa, architektura zorientowana na usługi, itd.). System Odra

jest raczej narzędziem dostarczającym mechanizmów umożliwiających zbudowanie takich

konfiguracji. Ze względu na wysokopoziomowe usługi dostarczane przez system (takie jak np.

62

Page 63: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

język programowania/zapytań, trwałość, transakcje, bezpieczeństwo, komunikacja rozproszona,

itd.) i w dużym stopniu deklaratywny charakter programowania, użytkownik może użyć systemu

Odra do wyrażenia wielu różnych konfiguracji systemów baz danych. Poniżej zaprezentujemy kilka

przykładowych, popularnych sytuacji jakie można zrealizować na bazie systemu Odra.

System samodzielny (scentralizowany)

Najprostsza sytuacja zachodzi wówczas, gdy system Odra pełni rolę scentralizowanego środowiska

uruchomieniowego programów SBQL. Jeśli budowana jest aplikacja biznesowa, realizująca

złożone operacje na danych masowych, wówczas SBQL mógłby potencjalnie zastąpić tradycyjne

języki programowania służące do tego celu. Zintegrowanie języka programowania z konstrukcjami

języka zapytań oraz inne mechanizmy znane z baz danych pozwalają znacząco przyspieszyć

programowanie aplikacji baz danych w stosunku do języków programowania ogólnego

przeznaczenia, czy nawet popularnych języków skryptowych.

jOdraAplikacja

SBQLProgram

SBQL

AplikacjaJava

CLI

Filtr XML

Dokument XML

Rys. 2: Architektura systemu scentralizowanego

Rysunek przedstawia przykładową konfigurację systemu scentralizowanego. System Odra pracuje

w tle, zarządzając danymi przechowywanymi na dysku i pamięci operacyjnej. Z systemu korzystają

dwie aplikacje wyposażone w GUI. Pierwsza z nich jest napisana w Javie i łączy się bazą danych w

tradycyjny sposób, za pomocą JDBC. Druga z nich napisana jest w SBQL, jest przechowywana

oraz uruchamiana przez bazę danych.

Bazą danych można administrować za pomocą narzędzia linii poleceń o nazwie CLI (Command

Line Interface). System Odra posiada zestaw “filtrów”, których zadaniem jest importowanie do

bazy Odra danych pochodzących z różnych, heterogenicznych źródeł. Przykładem takiego filtru jest

filtr dla XML, który dzięki zdolności do importowania dokumentów XML pozwala na

manipulowaniu ich zawartością za pomocą SBQL (zamiast np. XQuery). Ponieważ model danych

63

Page 64: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

języka SBQL wspiera obsługę danych półstrukturalnych, możliwe jest wyrażenie w nim dowolnego

dokumentu XML.

Architektura klient-serwer

Odra może być również wykorzystana do budowy systemów zgodnych z architekturą klient-serwer.

Ponieważ w systemie Odra złożoność procesów komunikacyjnych jest przezroczysta dla

programisty, wywołanie zdalnej procedury wiąże się często z wpisaniem jednej linii kodu.

jOdra jOdra

jOdra

Program SBQL

Program SBQL

SerwerWWW

AplikacjaSBQL

Program SBQL

Program SBQL

AplikacjaC#

SOAP

IDE

Przegl!darka

Brama WS

Rys. 3: Architektura systemu zbudowanego zgodnie z 3-warstwową architekturą klient-serwer

Powyższy rysunek przedstawia przykładową konfigurację systemu baz danych zbudowanego

w oparciu o trójwarstwową architekturę klient-serwer. Instalacja systemu Odra umieszczona

w prawym górnym rogu pełni rolę serwera bazy danych, instalacja z lewego górnego rogu

koncentruje się na realizacji logiki biznesowej (serwer aplikacyjny), komputer w prawym dolnym

rogu odpowiedzialna jest za warstwę prezentacji (cienki klient). Instalacja w lewym dolnym rogu

reprezentuje maszynę wykorzystywaną przez programistę pracującego nad aplikacją SBQL

działającą jako gruby klient. Cały kod aplikacji, łącznie z GUI może być napisany w SBQL.

Z językiem zintegrowane są mechanizmy języka zapytań oraz komunikacji rozproszonej, znacznie

zmniejszając (w porównianiu do tradycyjnych języków programowania) rozmiar kodu potrzebnego

do zaimplementowania w celu zapewnienia komunikacji. Oprócz tego na rysunku zaznaczono

również aplikację C# łącząca się z serwerem aplikacji opartym na Odra poprzez bramę dla

64

Page 65: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

WebServices. Brama taka udostępnia wybrane procedury bazodanowe jako usługi sieciowe,

umożliwiając wołanie ich za pomocą protokołu SOAP.

Poniżej przedstawiamy przykładowy kod źródłowy w języku SBQL realizujący prostą funkcję

biznesową w trójwarstwowej architekturze klient-serwer.

module client {dblink aps appuser/[email protected]

main() {aps.fire_employee(“Kowalski”);

}}

module appserver {dblink dbs dbuser/[email protected]

fire(name : string) {delete dbs.emp where lname = name;

}}

module dbserver {emp [0..*] : record { fname : string; lname : string; salary : integer; }

}

Rys. 4: Przykładowa aplikacja SBQL w architekturze klient-serwer

Federacyjna baza danych

Podstawową zaletą federacyjnych baz danych jest zapewnienie wirtualnego widoku na całość

rozproszonych danych, przy zachowaniu autonomii poszczególnych źródeł danych kontrybuujących

do federacji. W federacyjnych bazach danych opartych na systemach relacyjnych widok taki

implementuje się za pomocą mechanizmu perspektyw. Niestety takie rozwiązanie nie jest w pełni

przezroczyste ze względu na trudności aktualizacji zintegrowanych w ten sposób danych z poziomu

globalnego klienta federacyjnej bazy danych.

Ze względu na zastosowanie mechanizmu aktualizowalnych perspektyw stworzonego w SBA,

system Odra pozbawiony jest tej wady. Dzięki wirtualnym referencjom zwracanym przez takie

perspektywy oraz możliwości przeciążania działających na nich generycznych operacji, możliwa

jest aktualizacja dowolnych danych lokalnych.

Poniższy rysunek przedstawia przykładową sytuację, w której zastosowano mechanizm

aktualizowalnych perspektyw SBA. Centralną rolę odgrywa tutaj tzw. serwer integracyjny. Rolą

65

Page 66: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

serwera integracyjnego jest zapewnienie wirtualnej, globalnej przestrzeni rozproszonej bazy

danych, z której korzystają klienci.

jOdra jOdra

jOdraPerspektywa integracyjna

jOdraAplikacja

SBQL

Perspektywa kontrybucyjna

Perspektywa kontrybucyjna

Oracle

Oracle Wrapper

SQLServer

SQLServer Wrapper

Rys. 5: Architektura federacyjnej bazy danych opartej na aktualizowalnych perspektywach

Najważniejszym elementem serwera integracyjnego jest tzw. perspektywa integracyjna [14],

definiowana automatycznie lub przez programistę dokonującego integracji zasobów. Podstawowym

elementem takiej perspektywy jest wyrażenie będące zapytaniem do integrowanych serwerów.

Zapytanie to może mieć dowolną formę, ale zazywczaj zapewne będzie to zapytanie składające się

kilku podzapytań połączonych za pomocą operatora union (fragmentacja horyzontalna). Oprócz

tego, twórca perspektywy integracyjnej definiuje jedną lub kilka operacji generycznych: virtual

objects, on insert, on delete, on update, on retrieve. Operacje te dokładnie określają czynności,

jakie powinny być wykonane w przypadku wiązania nazwy pod którą dostępne są wirtualne dane

zwracane przez perspektywę, gdy do wnętrza wirtualnego obiektu o określonym globalnym

identyfikatorze wstawiany jest inny obiekt, gdy wirtualny obiekt jest usuwany z bazy danych,

aktualizowany, lub poddawany dereferencji. Zauważmy, iż ponieważ operacje virtual

objectsvirtual objects, on insert, on delete, on update i on retrieve implementowane są jako

procedury, istnieje możliwość zaimplementowania w ich wnętrzach operacji dowolnie złożonych.

66

Page 67: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Przykładowo, można w ten sposób zaprogramować replikację danych, logowanie operacji dla celów

późniejszej analizy związanej z bezpieczeństwem, zabronić korzystania z całości lub części

sfederowanej bazy danych w określonych godzinach, itp.

Perspektywa integracyjna nakłada na integrowane zasoby konieczność dostosowania ich do

określonego schematu, tzw. schematu integracyjnego. Jeśli schemat lokalny integrowanych

zasobów różni się od schematu integracyjnego, wówczas po stronie integrowanego zasobu

potrzebna jest perspektywa pełniąca rolę mediatora [38, 42]. Dzięki mechanizmom wbudowanym

w aktualizowalne perspektywy SBA, perspektywa taka może nie tylko przekształcać jeden schemat

na inny, ale również przekształcać dane (np. zarobki z jednej waluty na drugą).

Tworzenie aplikacjiSystem Odra dostarcza własnego języka zapytań opartego na SBQL. Służy on jednak nie tylko do

zadawania zapytań i modyfikowania bazy danych, ale również do tworzenia kompletnych aplikacji

baz danych. Mogą to być zarówno aplikacje pracujące po stronie serwera bazy danych/aplikacji

(a’la PL/SQL), jak również aplikacje klienckie (także takie, które są zaopatrzone są w GUI).

Aczkolwiek SBQL świetnie nadaje się do programowania logiki biznesowej, w wielu sytuacjach

dostęp do bazy danych Odra może być wymagany z poziomu tradycyjnego języka programowania

(np. Java, albo C#). W odpowiedzi na takie zapotrzebowanie, przewidziana została możliwość

dostępu do bazy danych za pomocą dobrze znanych interfejsów bazodanowych, takich jak JDBC,

czy ADO. W sytuacji takiej SBQL może być wykorzystywany jako język zapytań oraz język

programowania do tworzenia oprogramowania pracującego po stronie serwera bazy danych (a’la

PL/SQL).

W systemach relacyjnych praktycznie jedyną jednostką organizacyjną danych jest schemat

użytkownika, a wszystkie tabele istnieją w jednolitej, ogólnie dostępnej przestrzeni. System Oracle

posiada oprócz tego możliwość grupowania programów napisanych w PL/SQL w jednolite bryły

zwane pakietami. Charakterystyczną cechą języków programowania jest tymczasem

przechowywanie zarówno deklaracji zmiennych, jak i kodu innych abstrakcji programistycznych

w ramach tzw. modułów [66].

Podstawową jednostką organizacyjną bazy danych Odra jest również moduł. Podobnie jak

w nowoczesnych obiektowych językach programowania, moduł jest samodzielnym komponentem

systemu, grupującym zbiór obiektów bazy danych i posiadającym dobrze zdefiniowany interfejs.

67

Page 68: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Moduły wspomagają enkapsulację oraz ponowne użycie. Pozwalają także zorganizować bazę

danych w niezależne komponenty, nad którymi osobno pracować mogą różni programiści.

Podstawową różnicą w porównaniu z modułami znanymi z języków programowania jest to,

iż moduły w językach programowania mają charakter wirtualny i istnieją jedynie podczas

kompilacji (są bytami drugiej kategorii programistycznej). W systemie Odra tymczasem, podczas

czasu wykonania zarówno same moduły, jak i ich zawartość przyjmują postać fizyczną (są bytami

pierwszej kategorii programistycznej). Zawartością modułów mogą być zarówno procedury, klasy,

perspektywy, indeksy, ale również same dane zdefiniowane przez użytkownika. Obiekty te również

są bytami pierwszej kategorii programistycznej.

Kod źródłowy aplikacji napisanych w SBQL przechowywany jest w plikach systemu operacyjnego

po stronie klienta, gdzie może być zarządzany przez pewne środowisko programistyczne.

Po zmodyfikowaniu kodu źródłowego modułu przez programistę zainicjowaniu przez niego

kompilacji, środowisko takie wysyła kod źródłowy modułu do serwera bazy danych. Serwer

porównuje przesłane definicje obiektów pod względem ich zgodności ze skompilowanymi

wcześniej strukturami i nanosi odpowiednie poprawki na strukturę bazy danych i metabazy. Istnieje

również możliwość pracowania bezpośrednio na obiektach bazy danych (np. procedurach)

w sposób podobny jak w bazach danych - za pomocą narzędzia linii poleceń i odpowiednich

instrukcji DDL (np. dla procedur - instrukcji create procedure, delete procedure, itp.). Dowolna

zmiana struktury modułu powoduje również konieczność automatycznego przekompilowania

modułów zależnych od takiego modułu (t.j. importujących go).

Połączenia bazodanowe i komunikacja rozproszonaSystem Odra umożliwia przezroczystą integrację rozproszonych zasobów, zarówno danych,

jak i “usług”. Podstawowym mechanizmem zapewniającym komunikację rozproszoną jest obiekt

połączenia bazodanowego. Najważniejsze informacje jakie przechowuje taki obiekt to: nazwa hosta

docelowego, port na którym nasłuchuje proces LSNR docelowej bazy danych, nazwa modułu

docelowego oraz hasło użytkownika (nazwa użytkownika jest zawsze pierwszym elementem

globalnej nazwy modułu).

Jeśli nazwa obiektu połączenia bazodanowego jest częścią zapytania, wówczas podzapytania

wykonywane w środowisku tego obiektu w rzeczywistości wykonują się po stronie serwera na

który wskazuje dane połączenie bazodanowe. Przykładowo, jeśli użytkownik utworzy połączenie

68

Page 69: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

bazodanowe o nazwie link1 wskazujące na serwer odra1.pjwstk.edu.pl oraz połączenie o nazwie

link2 wskazujące na serwer odra2.pjwstk.edu.pl, wówczas następujące zapytanie:

link1.do_something(“par1”; “par2”; 999);

spowoduje zdalne wywołanie procedury na serwerze odra1.pjwstk.edu.pl.

do_something(”par1”; “par2”; 999)

wynik

Rys. 6: Wywołanie zdalnej procedury

Bardziej skomplikowane przypadki mają miejsce wówczas, gdy odwołania do zdalnych serwerów

są częścią bardziej skomplikowanego zapytania, np.:

print ((link1.emp union link2.emp) where ename = “Smith”).salary;

deref (emp where ename = “Smith”).salary

deref (emp where ename = “Smith”).salarywynik2

wynik1

wynik1unionwynik2

Rys. 7: Dekompozycja zapytań w środowisku rozproszonym

W takiej sytuacji zapytanie musi zostać zdekomponowane na podzapytania zgodnie z pewną regułą

dekompozycji. Reguła ta może mówić np., że zapytanie emp.name powinno zostać wysłane na

serwer odra1.pjwstk.edu.pl, a zapytanie dept.name powinno trafić na serwer odra2.pjwstk.edu.pl.

Rezultaty tych podzapytań mogą zostać następnie lokalnie zsumowane oraz wyświetlone na

ekranie.

PodsumowanieW rozdziale przedstawiliśmy naszą koncepcję narzędzia RAD wspomagającego tworzenie aplikacji

baz danych. Wspomnieliśmy, że narzędzie to rozpatrywać można na kilku różnych płaszczyznach:

obiektowego języka programowania zintegrowanego z językiem zapytań, systemu zarządzania

obiektową bazą danych, middleware opartym na koncepcjach znanych z federacyjnych baz danych.

Przedstawiliśmy również kilka przykładowych scenariuszy, w jakich takie narzędzie mogłoby

zostać zastosowane.

69

Page 70: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp
Page 71: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdział 5:Język SBQL w systemie Odra

WprowadzenieJęzyk SBQL stanowi jądro, wokół którego zbudowany jest system Odra. Podobnie jak PL/SQL

systemu Oracle, SBQL jest językiem wewnętrznym systemu zarządzania bazą danych w Odra.

Na tym jednak podobieństwa się kończą. SBQL jest obiektowym językiem programowania

z mocno zintegrowanym językiem zapytań. Zapytania przyjmują w nim formę wyrażeń,

a powiązanie pomiędzy konstrukcjami imperatywnymi i deklaratywnymi można określić jako

bezszwowe. W niniejszym rozdziale przedstawimy nieformalny opis składni i semantyki tego

języka. Nie opisujemy kilku bardziej zaawansowanych konstrukcji (np. klas), ponieważ ich

realizacja była przedmiotem osobnego podprojektu.

ModułyPodstawową jednostką organizacyjną programów SBQL jest moduł. Podobnie jak w nowoczesnych

obiektowych językach programowania, moduł jest samodzielnym komponentem grupującym zbiór

bytów programistycznych i posiadającym dobrze zdefiniowany interfejs. Moduły wspomagają

enkapsulację oraz ponowne użycie, pozwalają zorganizować aplikację w niezależne komponenty,

nad którymi osobno pracować mogą różni programiści.

Podstawową cechą odróżniającą moduły systemu Odra od modułów typowych języków

programowania jest to, iż ich skompilowana reprezentacja oprócz kodu aplikacji przechowuje

również obiekty bazy danych: wystąpienia zmiennych, indeksy, perspektywy, etc. Każda

71

Page 72: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

modyfikacja wprowadzona w module z ma charakter trwały. Istnieje możliwość zarówno tworzenia

i usuwania wystąpień zmiennych, jak i np. dodawania nowych procedur. W naszym prototypie nie

obsługujemy nietrwałych ani sesyjnych zmiennych globalnych, aczkolwiek wydaje się że

wprowadzenie ich nie powinno stanowić wielkiego problemu.

Poniżej przedstawiamy przykładowy kod źródłowy modułu wg składni jaką przyjęliśmy:

module test { import michal.firma;

prac : record { imie : string; nazwisko : string; pensja : integer; stanowisko : string; } [0..*]

policz_pracownikow() : integer { return count prac; }}

Moduł taki po przesłaniu do bazy danych jest kompilowany i dekomponowany na zbiór obiektów

bazy danych zgodnie ze strukturą podaną w osobnym rozdziale. Kod źródłowy modułu działa

zatem jak pewien rodzaj skryptu, którego zadaniem jest utworzenie obiektów bazodanowych.

Uproszczona gramatyka:

mod_decl ::= module name { mod_body_opt }

mod_body_opt ::= | mod_body

mod_body ::= import_list modfield_list | import_list | modfield_list

import_list ::= import_element | import_list import_element

import_element ::=

import cmpname ;

modfield_list ::= var_decl | proc_decl | typedef_decl | view_decl | link_decl

72

Page 73: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

| modfield_list var_decl | modfield_list proc_decl | modfield_list typedef_decl | modfield_list view_decl | modfield_list link_decl

Typy, nazwy i zmienneW naszym języku obsługujemy następujące typy wbudowane: integer, real, string, boolean.

Oprócz wbudowanych typów prostych, wprowadziliśmy również jeden typ złożony - record.

Zmienne typu rekordowego można deklarować zgodnie ze schematem in-line lub out-of-line.

W pierwszym przypadku definicję typu podajemy w miejscu przeznaczonym na nazwę typu,

w drugim - używamy konstrukcji definiującej typ o nazwie type (działa jako makro). Przykład:

type jakis_typ is record { x : integer; y : integer; }

a : jakis_typ; // deklaracja out-of-lineb : record { x : integer; y : integer; } // deklaracja in-line

Najważniejszą różnicą pomiędzy zmiennymi w systemie Odra oraz zmiennymi w tradycyjnych

językach programowania jest pojęcie liczności. Liczność określa dopuszczalną minimalną oraz

maksymalną liczbę wystąpień danej zmiennej. Drugą z tych wartości może być *, co oznacza że nie

istnieje górna granica ilości wystąpień zmiennej. Poniżej przykładowe deklaracje obejmujące

liczności:

a : integer [0..5];b : record { x : integer; y : integer; } [2..*];

Pierwsza deklaracja zakłada, że w pewnym środowisku może wystąpić od zera do pięciu wartości

typu integer o nazwie a. Po skompilowaniu programu, rezultatem zadeklarowania zmiennej a

będzie jedynie odpowiedni wpis w metabazie. Druga deklaracja zakłada istnienie co najmniej

dwóch złożonych wartości b. Kompilacja takiej deklaracji powoduje: a) umieszczenie

odpowiedniego wpisu w metabazie, b) utworzenie w bazie danych dwóch obiektów złożonych

z podobiektami x i y, oraz zainicjalizowanych wartościami domyślnymi. Jeśli zmienna

zadeklarowana jest z licznością niedomyślną (1..1), wówczas podczas czasu wykonania istnieje

możliwość wprowadzania nowych wystąpień tej zmiennej i usuwania istniejących za pomocą

instrukcji create i delete. Instrukcje te są tak zdefiniowane, by podczas wykonania związane z nimi

operacje nie naruszały ograniczeń nakładanych przez liczności (kontrola realizowana jest

dynamicznie).

73

Page 74: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Specjalną formą typu jest typ referencyjny, służący do określania związków pomiędzy obiektami.

W przeciwieństwie do typowych języków programowania, w miejscu po dwukropku nie podajemy

nazwy typu, ale nazwę zmiennej na którą wskazywać ma obiekt referencyjny. Przykładowo,

następująca deklaracja:

c : ref a;

oznacza, że c jest referencją na pewne wystąpienie (obiekt) zmiennej a. Konstrukcja taka jest

bardziej wygodna w modelowaniu pojęciowym (w UML [77, 79] asocjacje prowadzą do nazw

obiektów, a nie do typów), pozwala uniknąć kilku problemów charakterystycznych dla języków

posiadających wskaźniki, jak również umożliwia zrealizowanie kilku innych konstrukcji języka.

Domyślnie obiekt c inicjalizowany jest na wartość null. Wartość null można również później

podstawić na taką zmienną. Wprowadzono także operator is null, zwracający true gdy wartość

odpowiada null, i false gdy nie odpowiada. Dereferencja null powoduje błąd czasu wykonania.

W operacjach wyszukiwawczych (nawigacja, agregacja) obiekty z wartościami null traktowane są

jak nieistniejące dane. Wyjątkiem jest operator count, który podaje liczbę wszystkich obiektów

niezależnie od tego, czy ich wartość to null czy nie.

W celu uniknięcia zjawiska wiszących referencji, wprowadzony został mechanizm tzw. referencji

zwrotnych. Referencja zwrotna jest wewnętrznym (ukrytym przed programistą) wskaźnikiem

prowadzącym od obiektu wskazywanego przez obiekt referencyjny do obiektu referencyjnego.

Dzięki temu, jeśli obiekt wskazywany jest usuwany, automatycznie kasowane są równie obiekty

referencyjne wskazujące na niego. Jeśli skasowanie obiektu spowodowałoby naruszenie minimalnej

liczności którejś ze wskazujących na niego zmiennych referencyjnych, wówczas obiekt

referencyjny nie jest usuwany, a jego wartość ustawiana jest na null.

Charakterystyczną cechą zaprojektowanego przez nas zewnętrznego systemu typów jest możliwość

deklarowania zmiennych reprezentujących wartości nazwane pomocniczą zmienną. W ten sposób

odwzorowujemy sygnatury binderowe w zewnętrznym systemie typów. Przykładowo:

zmienna1 : x(integer);zmienna2 : x(y(integer [0..*]));

Pierwsza z powyższych deklaracji reprezentuje obiekty typu integer nazwane zmienną pomocniczą

x. Związanie nazwy zmienna1 powoduje zwrócenie bindera, którego nazwą jest x, a wartością

liczba całkowita. Druga deklaracja zakłada, że zmienna2 reprezentuje kolekcje wartości integer

nazwane zmienną pomocniczą y. Każdy z takich binderów nazwany jest nazwą pomocniczą x.

74

Page 75: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Poniżej kilka przykładowych operacji wykonanych na tak zadeklarowanych zmiennych:

zmienna1.x := 1;zmienna2.x.(create 2 as y);zmienna2.x.(create 3 as y);count zmienna2.x.y;

Uproszczona gramatyka konstrukcji umożliwiających wprowadzanie nowych zmiennych oraz

typów:

var_decl ::= name : type_decl

optcard ::= | card

card ::= [ INTEGER_LITERAL .. INTEGER_LITERAL ] | [ INTEGER_LITERAL .. * ]

typedef_decl ::= type name is type_decl

type_decl ::= name optcard ; | unnamed_rec_decl optcard | ref name optcard ; | name ( type_decl optcard ) optcard ;

type_decl_no_semicolon ::= name optcard | unnamed_rec_decl optcard | ref cmpname optcard | name ( type_decl optcard ) optcard

unnamed_rec_decl ::= record { rec_fields_opt }

rec_fields_opt ::= | rec_fields

rec_fields ::=

var_decl | rec_fields var_decl

cmp_name ::= name | cmpname . name

name ::= NAME_LITERAL

75

Page 76: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Procedury

Procedury w systemie Odra mają charakter typowy dla języków programowania. Podobnie jednak

jak większość elementów definiowanych w ramach modułów, procedury są bytami pierwszej

kategorii programistycznej. Oznacza to, że w każdym momencie procedury zdefiniowane w jakimś

module mogą być usuwane, jak również istnieje możliwość dodawania nowych procedur. W takiej

sytuacji moduł w którym nastąpiła tego rodzaju zmiana oraz moduły importujące go są

automatycznie przekompilowywane (sprawdzana jest poprawność odwołań do nazw, typy użytych

zmiennych itp.).

Poniżej kod przykładowej procedury:

a : integer [0..*];b : boolean;c : integer;

proca(val : integer [0..*]; cmp : ref integer) : boolean { return for any (val as x) x > cmp;}

Słowo kluczowe ref w deklaracji parametru formalnego procedury oznacza, że argument

przekazywany jest przez referencję, a nie przez wartość.

Istnieje kilka zasadniczych własności w składni definiującej procedury, które są charakterystyczne

wyłącznie dla systemu Odra. Różnice te przedstawimy korzystając z następującego przykładu:

a : integer [0..*];

procb(x : ref integer) : z(ref a) {

return (a as tmpa where tmpa > x).tmpa groupas z;

}

W powyższym listingu zaobserwować można następujące charakterystyczne własności:

1. Rezultatem działania naszej procedury może być wartość nazywana w SBA binderem

(nazwanym rezultatem). Rezultat taki deklaruje się podając nazwę bindera, a w nawiasie

dopuszczalny rezultat.

2. W przeciwieństwie do najbardziej popularnych obecnie języków programowania,

zdecydowaliśmy się zabronić zwracania referencji do obiektów lokalnych procedury.

Referencje do obiektów można zwracać, ale tylko do obiektów globalnych. Referencji takich

nie deklaruje się podając nazwy typu, ale nazwę zmiennej. Pamięć przeznaczona na

przechowywanie obiektów lokalnych rezerwowana jest na stercie, lecz zwalniana jest

76

Page 77: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

automatycznie po wyjściu z procedury. Między innymi dzięki tej własności uniknęliśmy

konieczności wprowadzania do systemu mechanizmu zbieracza nieużytków (garbage

collector).

3. Zarówno parametrem aktualnym, jak i rezultatem procedury może być dowolny rezultat

zapytania, w szczególności kolekcja wartości. Przykładowo, procedurę proca można wywołać

w następujący sposób: proca(bag 1, 2, 3; c).

Poniżej przedstawiamy gramatykę konstrukcji umożliwiających definiowanie procedur:

proc_decl ::= name ( proc_par_opt ) proc_type_opt { stmt_list_opt }

proc_type_opt ::= | : type_decl_no_semicolon

proc_arg_opt ::= | proc_arg_list

proc_arg_list ::= formal_par_decl | proc_par_list ; formal_par_decl

formal_par_decl ::= name : type_decl_no_semicolon

Instrukcje

Instrukcje mają podobny charakter, jak w typowych językach programowania. Poniżej ich

uproszczona gramatyka:

stmt_list_opt ::= | stmt_list

stmt_list ::= stmt | stmt_list stmt

stmt_block ::= { stmt_list_opt }

stmt ::= stmt_block | foreach_stmt | while_loop_stmt | do_while_loop_stmt | break_stmt | continue_stmt | return_stmt | update_stmt

77

Page 78: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

| insert_stmt | create_stmt | assign_stmt | variable_decl_stmt | if_stmt ;

variabe_decl_stmt ::= var_decl ;

assign_stmt ::= expr := assign_expr ;

assign_expr ::= expr

return_stmt ::= return expr ; | return ;

break_stmt ::= break ;

continue_stmt ::= continue ;

for_stmt ::= for ( assign_stmt ; expr ; assign_stmt ) stmt

for_each_stmt ::= foreach ( expr ) stmt

while_do_loop_stmt ::= while ( expr ) do stmt

do_while_loop_stmt ::= do stmt_block while ( expr ) ;

if_stmt ::= if ( expr ) stmt | if ( expr ) stmt else stmt

Wyrażenia

Wyrażenia w naszej implementacji SBQL przyjmują w większości typową formę zaproponowaną

w SBA. Semantyka ważniejszych operatorów objaśniona została w rozdziale 5. W tym punkcie

omówimy jedynie mechanizm działania operatorów create, :< (insert) oraz update.

Operator create służy do tworzenia nowych obiektów w postaci wystąpień zmiennych. Jego

argumentem jest zapytanie zwracające nazwaną wartość (binder), a wynikiem zbiór referencji do

utworzonych obiektów. Binder musi mieć taką samą nazwę jak zmienna zadeklarowana

w środowisku, w którym wykonywana jest operacja create. Nowe wystąpienie tej zmiennej

przyjmie wartość będącą wartością bindera. W szczególności, jeśli wartością bindera jest kolekcja

wartości, wówczas utworzone zostanie kilka wystąpień zmiennej. Jeśli utworzony ma zostać obiekt

złożony, wówczas binder powinien posiadać jako wartość zagnieżdżone bindery odpowiadające

78

Page 79: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

poszczególnym polom rekordu podanym podczas deklaracji zmiennej. Przed wykonaniem

operatora create system sprawdza czy nowe wystąpienie nie przekroczy maksymalnej liczności

obiektów.

Poniżej kilka przykładów wykorzystania operatora create:

x : integer [0..5];y : record { a : integer; b [0..*] : string; } [0..5];...create 1 as x;create 2 as x;create (1 as a, (bag “Ala ma kota”, “Kot ma Ale”) groupas b) as y;

Operator update jest podobny do :=. Jedyna różnica polega na tym, iż ma on charakter

makroskopowy. Ewaluacja operatora := zakończy się błędem czasu wykonania jeśli lewa lub prawa

strona zwróci kolekcję wartości. Rezultat zapytania podanego jako parametr dla update musi

zwrócić kolekcję dwuelementowych struktur, w których pierwsze pole oznacza l-wartość, a prawe -

r-wartość. Przykład wykorzystania operatora update podano poniżej. Zadaniem pierwszej operacji

jest zwiększenie wartości wszystkich wystąpień zmiennej x o 10, jeśli pierwotna wartość była

większa od 10. Druga operacja zwiększa wartość każdego pola a zmiennej y o 10.

update x as tmpx where tmpx > 10 join tmpx + 10;update y.(a, a + 10);

Operator :< umożliwia wstawianie dowolnych obiektów do wnętrza innych obiektów. Jego

działanie przypomina kombinację operacji create i delete. Utworzone obiekty posiadają takie

wartości, jakie posiadają obiekty zwrócone przez prawą stronę operatora. Lewa strona musi zwrócić

pojedynczą referencję, prawa strona - kolekcję referencji. Rezultatem są referencje obiektów

zwrócone przez create. Przykład wykorzystania:

(dept where name = “Sales”) :< (emp where sal < 3000);

Operacja delete (zdefiniowana jako instrukcja) realizuje funkcję odwrotną do create, czyli usuwa

wystąpienia zmiennych, których referencje zwraca zapytanie podane jako parametr. Przykład

zastosowania:

delete (x as tmpx where tmpx > 5).tmpx;delete y where a > 5;

Składnia wyrażeń podana jest poniżej:

expr ::= primary_expr | name_expr | unary_expr

79

Page 80: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

| range_expr | sets_expr | additive_expr | multiplicative_expr | conditional_expr | logical_expr | relational_expr | equality_expr | cast_expr | non_algebraic_expr | proc_call_expr | set_constr_expr | insert_expr

primary_expr ::= STRING_LITERAL | INTEGER_LITERAL | REAL_LITERAL | BOOLEAN_LITERAL | ( expr ) | null

name_expr ::= name

range_expr ::= expr [ expr ]

unary_expr ::= - expr | + expr | ref expr | deref expr | not expr | count expr | avg expr | min expr | max expr | unique expr | sum expr | exists expr | update expr | delete expr | create expr | bag expr | expr as name | expr groupas name | expr is null

sets_expr ::= expr union expr | expr minus expr | expr intersect expr

80

Page 81: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

| expr in expr | expr , expr

additive_expr ::= expr + expr | expr - expr

multiplicative_expr ::= expr % expr | expr * expr | expr / expr

conditional_expr ::= if ( expr ) expr | if ( expr ) expr else expr

logical_expr ::= expr or expr | expr and expr

relational_expr ::= expr < expr | expr > expr | expr <= expr | expr >= expr

equality_expr ::= expr = expr | expr <> expr

cast_expr ::= expr cast name

insert_expr ::= expr :< expr ;

non_algebraic_expr ::= expr . expr | expr where expr | expr join expr | expr orderby expr asc_desc_opt | forall ( expr ) expr | forany ( expr ) expr

asc_desc_opt ::= | asc | desc

proc_call_expr ::= name ( expr_list_opt )

expr_list_opt ::=

81

Page 82: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

| expr_list

expr_list ::= expr | expr_list ; expr

Perspektywy

Perspektywy w naszej implementacji składają się z czterech elementów: nazwy perspektywy, listy

opcjonalnych procedur redefiniujących operacje generyczne, listy opcjonalnych podperspektyw,

listy opcjonalnych pól dostępnych wewnątrz perspektywy.

Nazwa perspektywy ma charakter administracyjny. Posługuje się nią użytkownik chcący operować

na perspektywie jako rzeczywistym obiekcie bazy danych (np. w celu usunięcia perspektywy).

Operacja virtual objects odpowiedzialna jest za przeciążenie operacji wiązania nazw. Parametrem

tej operacji jest deklaracja zmiennej pod jaką widoczne będą wirtualne obiekty zwracane przez

perspektywę. Operacja on retrieve umożliwia przeciążenie operacji dereferencji realizowanej na

pojedynczej wirtualnej referencji. Zwracana wartość musi być zgodna z typem podanym jako

parametr. Operacja on update umożliwia przeciążenie operacji aktualizacji obiektu wirtualnego

(operatory update, :=, itd.). Operacja on delete przeciąża operację usuwania wirtualnego obiektu.

Operacja on insert przeciąża wstawianie obiektu do obiektu wirtualnego.

Poniższy listing przedstawia kod przykładowej perspektywy:

view dzialy_krakow_view { virtual objects dzialy_krakow : dk(ref dzialy) [0..*] { return (dzialy where “Krakow” in lokalizacja) as dk; }

on retrieve : nazwa(string) { return dk.nazwa as nazwa; }

view nazwa_view { virtual objects nazwa : n(ref nazwa) { return dk.nazwa as n; }

on retrieve : string { return n; } }

view zatrudnia_view { virtual objects zatrudnia : z(ref zatrudnia) [0..*] {

82

Page 83: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

return dk.zatrudnia as z; }

on insert (p : ref pracownicy) { d.(create ref p as zatrudnia); } }}

Poniżej prezentujemy gramatykę konstrukcji odpowiedzialnych za definiowanie perspektyw.

view_decl ::= view name { view_body_opt }

view_body_opt ::= | view_fld_list

view_fld_list ::= view_fld | view_fld_list view_fld

view_fld ::= on_bind | on_retrieve | on_update | on_delete | on_create | var_decl | proc_decl | typedef_decl | view_decl

on_bind ::= virtual objects name opt_card : type_decl_no_semicolon { stmt_list_opt }

on_retrieve ::= on retrieve : type_decl_no_semicolon { stmt_list_opt }

on_update ::= on update ( name : type_decl_no_semicolon ) { stmt_list_opt }

on_insert ::= on insert ( name : ref name ) { stmt_list_opt }

on_delete ::= on delete { stmt_list_opt }

Połączenia bazodanowePołączenie bazodanowe jest obiektem reprezentującym kanał komunikacyjny ze zdalnym serwerem

Odra. Każde takie połączenie zawiera następujące informacje: nazwa hosta docelowego, port na

83

Page 84: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

którym nasłuchuje proces LSNR docelowej bazy danych, nazwa modułu docelowego oraz hasło

użytkownika (nazwa użytkownika jest zawsze pierwszym elementem globalnej nazwy modułu).

Poniżej składnia konstrukcji deklarującej połączenie bazodanowe:

link_decl ::= dblink name cmpname / name @ cmpname : INTEGER_LITERAL | dblink name name_list

Porównywanie i podstawianie strukturalneW implementacji SBQL dla systemu Odra przyjęta została strukturalna zgodność typów. Dzięki tej

decyzji programista aplikacji bazy danych jest w stanie zrealizować znacznie więcej operacji za

pomocą jednej konstrukcji.

Relacja bycia podtypem zdefiniowane jest następująco. Typ strukturalny B jest podtypem typu A

wówczas, gdy wszystkie pola typu B posiadają nazwy takie jak przynajmniej część pól typu A, oraz

typy porównywanych pól są ze sobą zgodne. Kolejność wystąpienia poszczególnych pól w obu

typach jest dowolna. Typy rekurencyjny są zabronione.

Jeśli typ B jest podtypem typu A, wówczas zmienna tego typu może znaleźć się po prawej stronie

operatora podstawiania (wliczając operator update) oraz operatora porównania. W czasie

wykonania, porównywanie dwóch wartości polega na zanalizowaniu czy poszczególne pola

zmiennej typu B odpowiadające polom struktury równe są takim samym polom w obiekcie

zmiennej typu A. Podstawianie strukturalne przebiega podobnie jak porównywanie. Poniżej prosty

przykład ilustrujący omawiane założenie:

x : record { a : integer; b : integer; c : integer; }y : record { b : integer; a : integer; }z : record { a : integer; b : integer; d : integer; }

x := y;x := 1 as a, 2 as b, 3 as c;x := z; // zabronione!y := x; // zabronione!y := 1 as a, 2 as b, 3 as d; // zabronione!

if (x = y) print “Struktury x i y sa sobie rowne”;

W ramach osobnego podprojektu system typów systemu Odra rozbudowany został o obsługę

nazwowej zgodności typów. Programista SBQL może zatem korzystać z obu tych technik.

84

Page 85: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

DereferencjaDereferencja jest operacją polegającą na uzyskaniu wartości obiektu na podstawie jego referencji.

Dla obiektów prostych rezultatem operacji dereferencji jest po prostu wartość pobrana

z odpowiedniego obiektu bazy danych. Dla obiektu złożonego dereferencja jest strukturą binderów

odzwierciedlających poszczególne pola tego obiektu. Przykładowo, dla obiektu złożonego i0

<i0, “emp”, <i1, “name”, “Jan Kowalski”> <i2, “sal”, 8000> <i3, “works_in”, i4>>

rezultatem dereferencji jest następująca struktura:

struct { name(“Jan Kowalski”), sal(8000), works_in(i4) }

PodsumowanieW rozdziale przedstawiliśmy skrótowy, nieformalny opis składni i semantyki języka

programowania powstałego poprzez rozbudowanie języka SBQL. Język ten może pełnić funkcję

typowego języka programowania aplikacji biznesowych, jak i tradycyjnie rozumianego,

obiektowego języka zapytań. Podstawową cechą naszego rozszerzenia SBQL jest to, iż zapytania

traktowane są jako wyrażenia oraz są bezszwowo zintegrowane z pozostałymi kontrukcjami języka.

85

Page 86: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp
Page 87: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdział 6:Optymalizacja zapytań rozproszonych

WprowadzenieZe względu na bardzo duży czas dostępu do rozproszonych zasobów, potrzebna jest specjalna

strategia ewaluacji zapytań operujących na takich danych. W tym rozdziale prezentujemy kilka

bardzo podstawowych metod optymalizacji zapytań SBQL opartych na ich dekompozycji na

podzapytania. Podzapytania te przesyłane są na serwery w postaci tekstowej, a zwracane przez nie

wyniki są następnie odpowienio lokalnie scalane. Czasami nie można w wygodny sposób rozdzielić

zapytania na podzapytania. W takich sytuacjach korzystamy z szeregu technik umożliwiających

przepisanie zapytania do równoważnej postaci, ale dającej się łatwiej zdekomponować na

podzapytania. Inna technika jaką stosujemy podobna jest do półzłączeń (semi-joins) znanych

z relacyjnych baz danych. W naszym przypadku polega ona na przesyłaniu razem z zapytaniem

głównym rezultatu jakiegoś jego podzapytania ewaluowanego na innym serwerze.

Połączenia bazodanowe Podstawowym mechanizmem komunikacyjnym wprowadzonym do systemu Odra są połączenia

bazodanowe. Połączenie bazodanowe reprezentuje kanał komunikacyjny pomiędzy dwoma

serwerami bazodanowymi oraz ukrywa przed programistą SBQL złożoność procesów

komunikacyjnych. Przykładowo, połączenie zadeklarowane poniżej

dblink testlink michal.myapp.hr/[email protected]:8888;

reprezentuje kanał komunikacyjny z serwerem odra.pjwstk.edu.pl na porcie 8888. W naszym

prototypie deklaracja taka może być umieszczona w kodzie źródłowym modułu, albo też dodawana

87

Page 88: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

ręcznie za pomocą polecenia administracyjnego create dblink. Parametr lokalizujący docelową

bazę danych posiada również podstawowe informacje związane z bezpieczeństwem (nazwa

użytkownika, hasło), jak również globalną nazwę modułu mającego stanowić środowisko

wykonania zdalnych operacji SBQL. Następująca instrukcja

testlink.test();

spowoduje wykonanie procedury test() na serwerze odra.pjwstk.edu.pl, znajdującej się w module

michal.myapp.hr (pod warunkiem, że podano poprawne hasło użytkownika michal). Podobnie,

instrukcja

print testlink.(emp where name = “Kowalski”).salary;

spowoduje wyszukanie pensji pracownika o nazwisku Kowalski w zdalnej bazie danych.

Oprócz zwykłych połączeń bazodanowych wprowadzono również połączenia grupowe. Połączenie

grupowe reprezentuje kilka połączeń pojedynczych dostępnych pod jedną nazwą. Poniżej przykład

deklaracji takiego połączenia:

dblink systemsab using systema, systemb;

Wywołanie dowolnego zapytania w kontekście połączenia systemsab realizowane jest jako suma

rezultatów tego zapytania wykonanych osobno na serwerach systema i systemb. Przykładowo,

zapytanie systemsab.connections rozwijane jest podczas kompilacji do zapytania

systema.connections union systemb.connections

Referencje do zdalnych obiektówW związku z tym, iż niektóre zapytania do zdalnych zasobów mogą zwracać referencje, a nie

wartości proste, niezbędne stało się rozszerzenie identyfikatora obiektu (OID) o informacje

umożliwiające jednoznaczne zidentyfikowanie zdalnego obiektu. Identyfikator taki przyjmuje

postać podobną do IOR w CORBA, oraz reprezentowany jest przez czwórki o następującej postaci:

<adres serwera, port nasłuchu, nazwa schematu użytkownika, lokalny identyfikator obiektu>

Taki identyfikator jest traktowany na równi ze zwykłymi referencjami do lokalnych zmiennych.

Może znajdować się na stosach, przekazywany jako argument do procedury, przetwarzany przez

operatory makroskopowe etc. Zabraniamy jednak możliwości tworzenia obiektów referencyjnych

do zdalnych obiektów.

Ze względu na podstawowe mechanizmy bezpieczeństwa jakie zdecydowaliśmy się zapewnić,

dereferencja zdalnej referencji również wymaga specjalnego potraktowania. Realizacja takiej

88

Page 89: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

operacji polega na sprawdzeniu, czy w schemacie użytkownika realizującego operację dereferencji

znajduje się przynajmniej jedno połączenie bazodanowe prowadzące do zdalnego serwera którego

adres przechowywany jest w referencji. Oprócz tego, porównywane są nazwy schematów. Jeśli

zidentyfikowane w ten sposób połączenie bazodanowe umożliwia kontakt ze zdalnym serwerem,

wówczas realizowana jest za jego pomocą zdalna operacja dereferencji.

Ewaluacja zapytań bez optymalizacji rozproszonej Zapytania korzystające z zasobów zdalnych mogą być realizowane z użyciem standardowych

metod implementacyjnych przyjętych dla SBQL. Warunkiem jest przedefiniowanie operacji nested

w taki sposób, aby operacja ta działając na identyfikatorze obiektu reprezentującego połączenie

bazodanowe wyznaczała nowe środowisko na podstawie środowiska zdalnego. Koncepcyjnie,

rezultatem takiej operacji dla obiektu złożonego byłby zbiór binderów z wartościami będącymi

zdalnymi referencjami do jego podobiektów. Bindery takie można umieścić na stosie

środowiskowym, a następnie przetwarzać w normalny sposób (uwzględniając oczywiście operację

dereferencji dla zdalnych obiektów).

Ze względu na znaczne opóźnienia implikowane przez operacje związane z dostępem do danych

poprzez sieć komputerową, w środowisku rozproszonym standardowy sposób ewaluacji zapytań

może nie prowadzić do rezultatu akceptowalnego wydajnościowo. Optymalizacja staje się więc

koniecznością.

Rozpatrzmy następujące zapytanie do zdalnych danych:

testlink.emp where name = "Smith"

Typowa ewaluacja tego zapytania polega na wykonaniu lewej strony operatora where, a następnie

dla każdego elementu będącego wynikiem lewej strony - wykonanie prawej strony. Dzięki

zmodyfikowaniu operacji nested w sposób opisany powyżej, na stos środowiskowy trafiają bindery

ze zdalnymi identyfikatorami obiektów emp. Wykonane zatem może być zapytanie emp, którego

rezultat odkładany jest na stosie rezultatów. Dalsza ewaluacja zapytania przebiega zgodnie

z następującym pseudokodem:

// rezultat operacji where BagResult bag = new BagResult();

// zdjecie ze stosu rezultatu zapytania testlink.emp Result res = stack.pop();

// prawe podzapytanie where

89

Page 90: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

foreach (Result r in res) { stack.openScope(); nested(r); // *

// lewe podzapytanie operatora = stack.bind("name");

// prawe podzapytanie operatora = stack.push(new StringResult("Smith"));

// zdjecie rezultatow String s2 = ((StringResult) stack.pop()).value;

ReferenceResult r1 = (ReferenceResult) stack.pop(); String s1 = (StringObject) r1.deref(); // *

// operacja porownania if (s1.equals(s2)) bag.addResult(r); stack.closeScope(); }

qres.push(bag);

Gdyby informacje o pracownikach składowane były w zdalnej bazie danych, a przetwarzanie

zapytania realizowane byłoby po stronie klienckiej, wówczas przedstawiony wyżej algorytm

musiałby odwoływać się do zdalnego serwera w miejscach oznaczonych przez nas za pomocą *

(nie wliczając odwołania związanego z ewaluacją zapytania testlink.emp). W naszym algorytmie

posiadamy dwa takie miejsca:

1. Wyznaczenie wnętrza obiektu przechowywanego na serwerze wymaga przesłania identyfikatora

obiektu i odebrania binderów z globalnymi identyfikatorami jego podobiektów.

2. Zamiana identyfikatora obiektu przechowywanego na serwerze na jego wartość (dereferencja)

wymaga przesłania identyfikatora obiektu i odebrania jego wartości w postaci ciągu znaków.

Co gorsza, obie operacje realizowane są dla każdego pracownika osobno, dodatkowo spowalniając

nasz algorytm. Dla tysiąca pracowników, oznaczałoby to dwa tysiące odwołań do zdalnej bazy

danych. Sytuacja taka jest nieakceptowalna, stąd geneza metody optymalizacji zapytań przez

dekompozycję dużego zapytania na podzapytania, przedstawionej w kolejnych punktach tego

dokumentu. Celem tej techniki jest spowodowanie, aby zapytania trafiały do danych, a nie

odwrotnie.

90

Page 91: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Nasze zapytanie mogłoby zostać zrealizowane znacznie wydajniej w środowisku rozproszonym,

gdyby w całości zostało wykonane po stronie serwera. Klient powinien zatem wysłać je w formie

tekstowej na serwer, a następnie odczytać wynik. Problem polega na tym, że niektóre zapytania

mogą odwoływać się jednocześnie do kilku serwerów. Potrzebny jest zatem mechanizm

umożliwiający wyznaczenie który fragment zapytania może zostać wysłany do serwera A, który do

serwera B, który powinien zostać zrealizowany lokalnie, itp.

Dekompozycja zapytańDekompozycja zapytań polega na podzieleniu zapytania na niezależne fragmenty, które mogą

zostać wysłane do wykonania na różnych komputerach. W celu wyznaczenia tych fragmentów,

korzystamy z techniki dekorowania drzewa składniowego nazwami serwerów. Jeżeli pewne

podzapytanie odwołuje się do danych składowanych na zdalnym serwerze, wówczas węzły drzewa

składniowego reprezentujące to podzapytanie dekorowane są nazwą serwera do którego się

odwołują. Jeżeli dane poddrzewo udekorowane jest w całości taką nazwą, wówczas zapytanie

reprezentujące to poddrzewo może być wysłane na ten serwer.

Globalna rozproszona metabaza

Do statycznej analizy programów SBQL niezbędna jest struktura nazywana metabazą. Statyczna

analiza zapytań niezbędna jest do zrealizowania statycznej kontroli typów, jak i wielu rodzajów

optymalizacji. Wykorzystujemy ją również przy dekompozycji zapytań.

Globalną rozproszoną metabazą nazywać będziemy metabazę, która składa się z: 1) metabazy

bieżącego modułu, w którym ewaluowane jest zapytanie 2) metabaz modułów przez niego

importowanych, 3) metabaz zdalnych modułów (i modułów przez nie importowanych) wszystkich

połączeń bazodanowych wykorzystywanych w zapytaniu.

Przed rozpoczęciem procedury dekorowania węzłów drzewa składniowego, w zapytaniu

wyszukiwane są odwołania do połączeń bazodanowych, a do wskazywanych przez nie serwerów

wysyłane są żądania przekazania odpowiednich danych, umożliwiających skonstruowanie globalnej

metabazy. Otrzymane w ten sposób obiekty podłączane są jako podobiekty do obiektów lokalnej

metabazy reprezentujących połączenia bazodanowe.

Po skonstruowaniu globalnej rozproszonej metabazy, przechodzimy do etapu dekorowania węzłów

drzewa składniowego nazwami serwerów.

91

Page 92: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Dekorowanie węzłów drzewa składniowego

W celu zrealizowania opisywanego mechanizmu dekompozycji zapytań, dokonujemy

następujących modyfikacji w strukturach wykorzystywanych przez kompilator SBQL:

1. Wszystkie węzły AST posiadają pole przechowujace informacje o nazwie serwera, na którym

mają zostać zrealizowane. Pole takie może być zaimplementowane np. jako referencja do

obiektu–połączenia bazodanowego reprezentujacego zdalną bazę danych, albo jako globalna

nazwa jednoznacznie identyfikująca dane połączenie w całej bazie danych.

2. Sygnatury operacji (rezultaty operacji podczas statycznej analizy zapytań) posiadają również

jedno pole mówiące o tym, przez jaki serwer zwrócone będą reprezentowane przez nie rezulaty

zapytania.

Procedura dekorowania węzłów drzewa składniowego polega na statycznej ewaluacji zapytania

z użyciem globalnej rozproszonej metabazy. Poczynając od najprostszych elementów, dla każdego

podzapytania wyznaczane są serwery, na których te podzapytania powinny zostać wyewoluowane.

W zależności od rodzaju węzła AST, procedura jego dekorowania, oraz oznaczania sygnatury

operacji jest inna:

• Nazwy. W zależności od wartości uzyskanej poprzez związanie nazwy mogą zdarzyć się dwie

sytuacje:

• Jeśli wartością tą jest referencja, wówczas w sygnaturze oraz w AST ustawiana jest wartość

wskazująca na połączenie bazodanowe uzyskane z metabazy. Zaczynając od uzyskanej

referencji należy w tym celu przenawigować w górę drzewa obiektów metabazy, aż do

napotkania obiektu połączenia bazodanowego. Jeśli obiekt połączenia nie może zostać

znaleziony, wówczas wiadomo że nazwa reprezentuje obiekt lokalny. W takim przypadku

sygnatura oraz węzeł AST oznaczane są nazwą localhost.

• Jeśli uzyskaną wartością nie jest sygnatura referencyjna, wówczas nazwa serwera pobierana

jest z tej sygnatury. Węzeł AST dekorowany jest tą samą nazwą.

• Literały. Pole sygnatury operacji reprezentującej połączenie bazodanowe ustawiane jest na

wartość nieznane, oznaczającą że ewaluacja może nastąpić w dowolnym miejscu. Węzeł AST

dekorowany jest tą samą wartością.

92

Page 93: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• Operatory dwuargumentowe. Po udekorowaniu obu poddrzew danego węzła nazwami

połączeń, musi zostać podjęta decyzja na temat tego, gdzie zostanie wykonana operacja związana

z danym operatorem. Wyobrazić można sobie następujące przypadki:

• Jeżeli sygnatury obu podzapytań oznaczone są nazwą tego samego połączenia, wówczas

nazwa ta przydzielana jest również węzłowi operatora oraz sygnaturze operacji

reprezentowanej przez operator.

• Jeżeli sygnatury obu podzapytań oznaczone są innymi nazwami, wówczas węzeł operatora

oraz sygnatura wynikowa jego ewaluacji otrzymują nazwę localhost.

• Jeśli jedna z sygnatur oznaczona jest wartością nieznane, wówczas węzeł reprezentujący tę

operację oraz sygnatura reprezentująca rezultat jego ewaluacji dekorowane są nazwą

połączenia z sygnatury drugiego podzapytania. Ta sama wartość trafia do sygnatury operacji

reprezentującej operator oraz reprezentującego go węzła AST.

• Jeśli obie sygnatury oznaczone są wartością nieznane, wówczas węzeł operatora dekorowany

jest wartością nieznane. Ta sama wartość trafia do sygnatury operacji reprezentującej operator.

Specjalna sytuacja dotyczy sygnatur wariantowych. Jeśli analizowany jest operator

niealgebraiczny, a jego lewa strona zwraca wariant, wówczas drzewo skladniowe musi zostać

“rozszczepione” na kilka postaci. Każda postać takiego drzewa dotyczy jednej sytuacji określonej

w sygnaturze wariantowej. Dla każdej postaci drzewo składniowe dekorowane jest następnie

w normalny sposób, po czym poszczególne postacie porównywane są ze sobą. Jeśli dla którejś

formy AST jakiś węzeł oznaczony został inną nazwą niż pozostałe węzły, wówczas w finalnej

wersji AST węzeł ten ukolorowany jest nazwą localhost.

• Operatory jednoargumentowe. Węzeł operatora dekorowany jest tą samą nazwą, jaka została

przydzielona dla sygnatury jego argumentu. Tą samą nazwą oznaczana jest sygnatura

reprezentująca rezultat działania operatora.

Po zanalizowaniu całego AST i powrocie do korzenia, wyszukiwane są wszystkie węzły oznaczone

nazwą nieznane. Węzły takie oznaczane są nazwą localhost.

Przesyłanie podzapytań do serwerów Drzewo składniowe udekorowane nazwami serwerów może zostać podzielone na

poddrzewa i przesłane do odpowiednich serwerów celem ich zrealizowania. Idąc od korzenia,

interpreter przechodzi AST sprawdzając nazwy serwerów, jakimi udekorowane zostały

93

Page 94: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

poszczególne węzły. Jeśli nazwą tą jest localhost, wówczas wiadomo iż operator musi zostać

wykonany lokalnie. W takim przypadku interpreter kontynuuje proces przechodzenia po drzewie

składniowym. Jeśli nazwa jest inna niż localhost, wówczas wiadomo iż całe poddrzewo może

zostać wysłane na serwer identyfikowany tą nazwą. W tej sytuacji interpreter przerywa

przechodzenie w głąb drzewa, zamienia poddrzewo na tekstowe zapytanie i wysyła je na

odpowiedni serwer.

Aby zapytanie takie miało sens dla docelowej bazy danych, tekstowa forma zapytania pozbawiona

musi być uprzednio wszelkich operacji realizowanych na połączeniach bazodanowych. Ponieważ

wszystkie operacje oprócz . (kropka) są zabronione dla obiektów reprezentujących połączenia

bazodanowe (nie mają sensu), dlatego odwołania do nich zawsze będą miały formę

nazwa_połączenia.zapytanie. Aby dostosować zapytanie do odpowiedniej postaci wystarczy

wyszukać nazwę połączenia bazodanowego, a następnie zastąpić nadrzędną operację . za pomocą

jej prawej strony.

Jako prosty przykład rozpatrzmy następujące zapytanie:

(s1.employee where name = "Kowalski").(imie + "" + nazwisko);

Jak widać na poniższym rysunku, korzeń drzewa składniowego tego zapytania udekorowany został

nazwą s1. Oznacza to, że całe zapytanie

(employee where name = "Kowalski").(imie + "" + nazwisko);

może zostać wysłane na serwer s1 i tam wykonane.

s1

+

imie " "

nazwisko

s1

.

s1

"Kowalski"

where

name

.

s1 employee

s1

s1

s1

s1

s1

=

s1

s1

+s1

s1

Rys. 8: Drzewo składniowe dla zapytania przykładowego zapytania udekorowane nazwami serwerów

Następujący przypadek jest nieco bardziej złożony, ponieważ w zapytaniu wystepują odwołania do

trzech serwerów:

(s1.employee union s2.employee) where salary > s3.sal_limit;

94

Page 95: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

>

s3

where

localhost

employee

union

s2

.

s1 employee

s1

s1

s1

localhost

s2

. s2

sal_limit

localhost

salary .

s1

s3 s3

s3

s2

Rys. 9: Drzewo składniowe dla pierwszego wariantu (gdy salary dotyczy s1.employee)

Dodatkowo, rezultatem operatora union podczas kompilacji jest sygnatura wariantowa. Ponieważ

operator where działa na tej sygnaturze, dlatego jego prawa strona musi zostać “rozszczepiona”

w celu obsługi dwóch sytuacji: 1) gdy analizowany jest obiekt employee z serwera s1, 2) gdy

analizowany jest obiekt z serwera s1. W pierwszym przypadku węzeł nazwy salary udekorowany

zostaje nazwą s1, a w drugim - nazwą s2. Po analizie obu form uzyskanych poddrzew dochodzimy

do wniosku, iż wiązanie nazwy salary powinno zostać zrealizowane lokalnie (stąd nazwa localhost

w ostatecznej formie udekorowanego AST).

Końcowe zapytanie może zostać zrealizowane poprzez wysłanie zapytania employee na serwery

s1 i s2, lokalnym zsumowaniu obu wyników, a następnie wysłaniu zapytania sal_limit na serwer s3,

i lokalnego porównania otrzymanej wartości z pensją poszczególnych pracowników.

>

s3

where

localhost

employee

union

s2

.

s1 employee

s1

s1

s1

localhost

s2

. s2

sal_limit

localhost

salary .

s2

s3 s3

s3

s2

Rys. 10: Drzewo składniowe dla drugiego wariantu (gdy salary dotyczy s2.employee)

W dalszej części opracowania oprócz graficznych reprezentacji udekorowanego drzewa

składniowego pisać będziemy zapytania w formie tekstowej. Powyższe zapytanie zgodnie z naszą

notacją przyjmie następującą postać:

(s1s1 .s1 employees1 unionlocalhost s2s2 .s2 employees2) wherelocalhost salarylocalhost >localhost s3s3 .s3 sal_limits3;

95

Page 96: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

>

s3

where

localhost

employee

union

s2

.

s1 employee

s1

s1

s1

localhost

s2

. s2

sal_limit

localhost

salary .

localhost

s3 s3

s3

s2

Rys. 11: Ostatecznie udekorowane drzewo składniowe przykładowego zapytania

Przepisywanie zapytańW poprzednim punkcie pokazaliśmy, że jeśli w zapytaniu występuje odniesienie tylko do jednego

serwera, wtedy może ono zostać w całości wysłane do wykonania na ten serwer. Ten scenariusz

w rzeczywistości może być nieco bardziej skomplikowany. Po pierwsze, niektóre zapytania są tak

skonstruowane, iż ich ewaluacja powoduje wielokrotne odwoływanie do zdalnych zasobów, lub też

powoduje przesłanie niepotrzebnych danych. Po drugie, zapytania mogą być tak skonstruowane, że

występujące w nich nazwy odwołujące się do zdalnych zasobów są ze soba na tyle splątane,

iż zapytanie nie może być łatwo zdekomponowane na podzapytania. Okazuje się, że niektóre

zapytania mogą zostać automatycznie przepisana w taki sposob, aby ich ewaluacja w systemie

rozproszonym była mniej kosztowna. W tym punkcie przedstawiamy kilka obserwacji związanych

z taką optymalizacją.

Przemienność

Wyrażenia składające się z ciągu podwyrażeń połączonych operatorami algebraicznymi mogą być

w prosty sposób zoptymalizowane przy użyciu własności przemienności i łączności niektórych

operatorów. Przykładowo ewaluacja poniższego zapytania:

s1.val1 + s2.val2 + s1.val3;

bez optymalizacji powoduje konieczność dwukrotnego skontaktowania się z serwerem s1. Pierwszy

raz w celu uzyskania wartości zmiennej val1, drugi raz w celu uzyskania wartości zmiennej val3.

Ilustruje to poniższy zapis, odzwierciedlający miejsce wykonania poszczególnych operatorów:

s1s1 . s1val1s1 +localhost s2s2 .s2 val2s2 +localhost s1s1 .s1 val3s1;

Prosta zamiana miejsc zmniejsza liczbę operacji na serwerze s1 do jednej:

s1s1 . s1val1s1 +s1 s1s1 .s1 val3s1 +localhost s2s2 .s2 val2s2;

96

Page 97: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdzielność

Niektóre operatory posiadają cechę rozdzielności względem innych operatorów. Cechę tę można

wykorzystac do takiego przepisania zapytania, aby zmniejszyć ilość danych przesyłanych przez

sieć.

Operatory arytmetyczne

Najprostszym przypadkiem jest rozdzielność mnożenia względem dodawania. Dzięki tej własności

następujące zapytanie:

s.val * s1.val1 + s.val * s2.val2 + s.val * s3.val3;

może zostać przepisane do nastepujacej postaci:

s.val * (s1.val1 + s2.val2 + s3.val3);

W ten sposób, zamiast trzech odwołań do serwera s, konieczne jest tylko jedno.

Operatory sumy zbiorów i iloczynu kartezjańskiego

Dużo większe korzyści niż w poprzednich przykładach może przynieść wykorzystanie

rozdzielności względem sumy zbiorów. Nastepujące zapytanie jest charakterystyczne dla

fragmentacji poziomej rozproszonej bazy danych:

(s1.employee union s2.employee union s3.employee).lname;

Zapytanie to wymaga przesłania na stronę klienta zdalnych referencji do wszystkich pracowników,

a następnie tylko ich nazwisk. Zapytanie to można jednak przepisać do bardziej wydajnej postaci:

s1.employee.lname union s2.employee.lname union s3.employee.lname;

Forma po przekształceniu jest dużo wydajniejsze w ewaluacji, gdyż wymaga przesłania mniejszej

ilości danych (od razu przesyłane są tylko referencje do nazwisk).

Czasami przydatna jest również sytuacja odwrotna. Ilustruje to poniższe zapytanie:

s1.employee join s2.get_date()union s3.employee join s2.get_date() union s4.employee join s2.get_date();

W tym wypadku lepiej jest wyciągnąć wspólną, niezależną od join część przed nawias, by wykonać

ją tylko raz:

(s1.employee union s3.employee union s4.employee) join s2.get_date();

Generalna zasada jest następująca:

97

Page 98: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• (s1.q1 union s2.q2 union s3.q3 ...) ∆ q ⇒ s1.q1∆ q union s2.q2∆ q union s3.q3∆ q ...

∆ oznacza jeden z następujących operatorów: . (kropka), where, join (jeśli q jest zależne od ∆)

• s1.q1∆ s.q union s2.q2 ∆ s.q union s3.q3 ∆ s.q ... ⇒ (s1.q1 union s2.q2 union s3.q3 ...) ∆ s.q

∆ oznacza: , (przecinek) lub join (jeśli s.q jest niezależne od ∆)

• (s1.q1, s2.q2, s3.q3 ...) ∆ q ⇒ s1.q1∆ q, s2.q2∆ q, s3.q3∆ q ...

∆ oznacza jeden z następujących operatorów: . (kropka), where, join (jeśli q jest zalezne od ∆)

Operatory agregujące i kwantyfikatory

Podobna sytuacja dotyczy operatorów agregujących i kwantyfikatorów. Tuta jednak zwykle

potrzebne są dodatkowe operatory łączące komponenty zapytania. Przykładowo, zamiarem

programisty formułującego poniższe zapytanie było policzenie wszystkich pracowników:

count (s1.employee union s2.employee union s3.employee);

Zamiast jednak przesyłać z wszystkich trzech serwerów referencje do wszystkich pracowników

i dopiero lokalnie ich policzyć, można od razu przesłać sumy cząstkowe ze wszystkich serwerów.

Sumy takie mogą posłużyć do wyliczenia sumy całościowej:

count s1.employee + count s2.employee + count s3.employee;

Generalna zasada w stosunku do operatorów agregujących i kwantyfikatorów jest następująca:

• ∆ (s1.q1 union s2.q2 union s3.q3 ...) ⇒ ∆ (∆ s1.q1 union ∆ s2.q2 union ∆ s3.q3)

∆ oznacza jeden z następujących operatorów: distinct, unique, min, max

• exists(s1.q1 union s2.q2 union s3.q3 ...) ⇒ exists s1.q1 or exists s2.q2 or exists s3.q3 ...

• ∆ (s1.q1 union s2.q2 ... union sx.qx) ⇒ ∆ s1.q1 + ∆ s2.q2 ... + ∆ sx.qx

∆ oznacza jeden z następujących operatorów: count, sum.

• avg (s1.q1 union s2.q2 ... union sx.qx) ⇒ (sum s1.q1 + sum s2.q2 ... + sum sx.qx) / x

• forall (s1.q1 union s2.q2 union s3.q3 ...) q ⇒

forall (s1.q1) q and forall (s2.q2) q and forall (s3.q3) q ...

• forany (s1.q1 union s2.q2 union s3.q3 ...) q ⇒

forany (s1.q1) q or forany (s2.q2) q or forany (s3.q3)

98

Page 99: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Przesyłanie wyników podzapytań razem z zapytaniamiCzasami operacje odwołujące się do zasobów osobnych serwerów są ze sobą na tyle splątane, że

przekształcenia zaprezentowane dotychczas nie wystarczają. W tej sekcji prezentujemy metodę

optymalizacyjną przypiminającą technikę semi-joins znaną z systemow relacyjnych.

Wprowadzenie

Rozpatrzmy następujące zapytanie:

(s1.department join s2.employee where ename = dname).(ename, dname, location);

Przypadek ten jest bardzo nieprzyjemny z punktu widzenia optymalizacji zapytań. Drzewo

składniowe tego zapytania przedstawione na rysunku poniżej wskazuje, iż zgodnie z naszymi

dotychczasowymi strategiami optymalizacyjnymi, zapytanie to może być zrealizowane jedynie

poprzez przesłanie referencji do wszystkich departamentów i wszystkich pracowników na komputer

klienta, który realizuje operację złączenia.

Prawdopodobnie jednak tylko niewielki procent pracowników posiada nazwiska takie jak nazwy

departamentów, zatem przesyłanie informacji o wszystkich pracownikach jest całkowicie

niepotrzebne. Dodatkowo, późniejszy dostęp do poszczególnych informacji na temat pracowników

i departamentów wymagał będzie wielokrotnej komunikacji z serwerem bazy danych.

where

. .

s1 department s2 employee

join =

ename dname

,

location,

ename dname

.

s1 s1

s1

s2 s2

s2

localhost

s2 s1

localhost

localhost

s2 s1

s1

localhost

localhost

localhost

Rys. 12: Drzewo składniowe przykładowego zapytania po udekorowaniu nazwami serwerów

Możemy na szczęście zastąpić podzapytanie odwołujące się do serwera s1 lub s2 jego rezultatem

poddanym dereferencji i wysłać je na drugi serwer razem z tak spreparowanym zapytaniem. Przy

takim podejściu powstaje jednak pytanie czy lepiej jest wysłać pracowników na serwer s1, czy tez

departamenty na serwer s2? Intuicyjnie możemy stwierdzić, że liczba departamentów każdej

organizacji jest mniejsza niż liczba ich pracowników. Inne pytanie jakie może się pojawić: czy

99

Page 100: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

należy przesyłać wszystkie wartości uzyskane z dereferencji, czy też tylko te które będą potrzebne

w dalszej części zapytania?

Nasze rozwiązanie tego problemu prowadzi do zastosowania optymalizacji kosztowej

zapytań i wykorzystania statystyk gromadzonych przez system i dotyczących obiektów bazy

danych. Przydatne mogą być przede wszystkim informacje na temat obiektów w danej kolekcji, np.

średnia wielkość wartości (np. średnia długość nazwiska), czy ilość obiektów. Statystyki mogą być

umieszczone w metabazie, zatem praktycznie nie zmienia się nic w dziedzinie dostępu do danych

potrzebnych do kompilacji. Rozszerzamy natomiast mechanizm analizy statycznej zapytań

o możliwość dekorowania węzłów drzewa składniowego o przewidywalny rozmiar rezultatu każdej

operacji. Rozmiar ten dosyć łatwo jest wyliczyć na podstawie sygnatury operacji oraz statystyk

przechowywanych w metabazie.

Można zauwazyć, iż splątanie odwołań do nazw obiektów przechowywanych na osobnych

serwerach następuje w bardzo konkretnej sytuacji. Zauważmy, że na powyższym rysunku

występują dwa rodzaje poddrzew udekorowanych tymi samymi nazwami serwerów. Pierwszym

rodzajem jest to, które wywodzi się od nazwy obiektu reprezentującego połączenie ze zdalną bazą

danych (zapytanie główne). Na rysunku reprezentuje ono zapytania s1.department i s2.employee.

Do drugiej grupy należą pozostałe poddrzewa udekorowane tymi samymi nazwami co te

poddrzewa (zapytanie zależne wobec zapytania głównego). Widać że poddrzewa te rozdzielone są

od siebie przynajmniej jednym węzłem operatora niealgebraicznego udekorowanym nazwą

localhost. Ta obserwacja pozwala nam przyjąć generalny wniosek mówiący kiedy należy

spróbować zastosować optymalizację poprzez wysyłanie na zdalne serwery zapytań razem

z wynikami niektórych ich podzapytań. Podstawowym celem tej metody będzie zbudowanie

takiego zapytania do serwera sx, aby mogło ono pobrać wszystkie dane niezbędne do ewaluacji

głównego (nieco zmodyfikowanego) zapytania, ale znajdujące się na tym serwerze sx.

Przykładowo, sięgając na serwer s1 za pomocą następującego zapytania:

(department groupas $s1_0)join $s1_0.(deref dname groupas $s1_1, dname groupas $s1_2, location groupas $s1_3);

będziemy w stanie wysłać rezultat tego zapytania (oznaczony za pomocą X) na serwer s2 razem

z następującym zapytaniem:

100

Page 101: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

(X join employee where ename = $s1_1).(ename, $s1_2, $s1_3);

Wyznaczanie planu wykonania zapytania

Pierwszym krokiem w opisywanej metodzie optymalizacyjnej powinno być zidentyfikowanie

największych możliwych poddrzew wywodzących się bezpośrednio z węzłów identyfikujących

połączenia bazodanowe. W ten sposób (po usunięciu węzłów operatorów nawigacji na s1 i s2) dla

przedstawionego powyżej zapytania dysponujemy dwoma głównymi zapytaniami, odpowiednio:

department (które ma zostać wysłane na s1) i employee (które ma zostać wysłane na s2).

Z uzyskanymi w opisany powyżej sposób zapytaniami głównymi muszą zostać związane pozostałe

poddrzewa udekorowane nazwami s1 i s2. Wyszukujemy zatem największe możliwe poddrzewa

udekorowane tymi nazwami i otrzymujemy następujące podzapytania: dname, dname, location

(dla s1) oraz ename, ename (dla s2). Ze względu na możliwość występowania nazw pomocniczych

w zapytaniach, niezbędne jest także wyznaczenie zależności pomiędzy tymi zapytaniami. Zapytanie

X jest zależne od zapytania Y, jeśli wszystkie nazwy występujące w X wiązane są sekcjach stosu

środowiskowego otwartych przez operator niealgebraiczny działający na zapytaniu Y. Jeśli

w zapytaniu X tylko niektóre nazwy zależne są od Y, a pozostałe nazwy zależne są od innego z tych

podzapytań, wówczas zapytanie X rozdzielane jest na kilka dodatkowych podzapytań, w których

taka zależność nie występuje. Takie zapytania powiększają zbiór podzapytań zidentyfikowanych

jako zależne od zapytań odwołujących się bezpośrednio do połączeń bazodanowych.

W kolejnym kroku optymalizator powinien zbudować wszystkie możliwe plany wykonania

zapytania uwzględniające możliwość wysłania rezultatu pewnego zapytania wraz z zapytaniem

głównym. Tworzony jest zatem plan uwzględniający ewaluację całego zapytania po stronie klienta

(zgodnie z pierwotnym udekorowaniem AST), a także wszystkie możliwe plany zakładające

przesłanie wyników pewnych (lub wszystkich) podzapytań razem z zapytaniem głównym.

Zadaniem tych zapytań jest umożliwienie wyznaczenia kosztu transferu danych potrzebnych do

ewaluacji pierwotnego zapytania. Aby wyliczyć ten koszt wykorzystujemy statystyki periodycznie

zbierane przez system zarządzania bazą danych. Statystyki te umieszczane są w metabazie razem

z deklaracjami obiektów. W naszym przypadku dla każdej deklaracji potrzebujemy dwóch wartości:

ilość obiektów w bazie danych oraz średnią wielkość wszystkich obiektów.

Załóżmy, iż metabaza serwera s1 przyjmuje przedstawioną poniżej postać. W nawiasach < >

podano statystyki aktualne w pewnym momencie.

101

Page 102: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

department [0..*] <ilosc: 10> : record { dname <ilosc: 1, wielkosc: 8B> : string; location <ilosc: 1, wielkosc: 10B> : string; address <ilosc: 1, wielkosc: 25B>: string;}

Serwer s1 przechowuje 10 obiektów department, z których każdy posiada jedno pole dname

(średnia wielkość 8 bajtów), jedno pole location (średnia wielkość 10 bajtów) oraz jedno pole

address (średnia wielkość 25 bajtów). Zakładając jako jednostkę kosztu ilość przesłanych danych

pomiędzy dwoma komputerami, koszt przesłania z serwera s1 wszystkich danych potrzebnych do

ewaluacji naszego zapytania głównego wynosi w tej sytuacji 430 bajtów.

Podobnie, przyjmijmy że metabaza serwera s2 przyjmuje następującą postać:

employee [0..*] <ilosc: 1000> : record { ename <ilosc: 1, wielkosc: 8B> : string; job <ilosc: 1, wielkosc: 10B> : string; salary <ilosc: 1, wielkosc: 4B>: integer;}

Koszt przesłania wszystkich informacji o pracownikach wynosi więc 22000 bajtów.

Dodatkowo, zakładamy że długość pojedynczej zdalnej referencji wynosi 20 bajtów.

Dysponując tymi danymi, dla analizowanego w tym punkcie zapytania, optymalizator może

wyznaczyć trzy plany wykonania:

1. Wykonanie zapytanie w pierwotnej formie, czyli bez przesyłania wyników. Oznacza to

przesłanie referencji do wszystkich obiektów employee (koszt: 1000 * 20 = 20000B)

i department (koszt: 10 * 20 = 200B).

Na podstawie sygnatury zwróconej poprzez zanalizowanie operatora join uzyskujemy

informację o tym, iż operator where operował będzie na zbiorze wielkości [0..10000].

Dla każdego elementu iloczynu kartezjanskiego zwroconego przez operator join, dwa razy musi

zostać związana nazwa ename (koszt: 2 * [0..10000] * 20 = [0..400000]B), a następnie każda

z otrzymanych w ten sposób referencji musi zostać poddana dereferencji (koszt: 2 * [0..10000]

* 8 = [0..160000]B). Oprócz tego, dwukrotnie musi zostać związana nazwa dname (koszt: 2 *

[0..10000] * 20 = [0..400000]B), oraz raz nazwa location (koszt: [0..10000] * 20 =

[0..200000]B). Referencje do obiektów location poddawane są raz dereferencji (koszt:

[0..10000] * 10 = [0..100000]B). Koszt przesłania wszystkich danych potrzebnych do ewaluacji

tego zapytania wynosi więc [0..400000 + 160000 + 400000 + 200000 + 100000]B =

[0..1260000]B. Klient musi komunikować się z serwerami 2 (wiązanie department i employee)

102

Page 103: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

+ 5 * [0..10000] (wiązanie nazw ename, dname, ename, dname, location) + 2 * [0..10000]

(dereferencja ename i dname) = [2..70000] razy.

2. Wysłanie na serwer s2 zapytania w formie

(X join employee

where ename = $s1_1).(ename, $s1_2, $s1_3);

gdzie X oznacza rezultat wykonania na serwerze s1 zapytania (department groupas $s1_0)

join

$s1_0.(deref dname groupas $s1_1,

dname groupas $s1_2,

location groupas $s1_3);

Rezultat tego zapytania składa się z kolekcji struktur, których pierwsze pole jest referencją do

obiektu department (20B), drugie pole jest wartością dname poddana dereferencji (8B), trzecie

pole jest referencją do obiektu dname (20B), a czwarte - referencją do location (20 B). Koszt

przesłania tego rezultatu z serwera s1 na stronę klienta wynosi [0..10 * 68]B = [0..680]B. Ten

sam rezultat musi zostać następnie wysłany razem z zapytaniem

(X join employee where ename = dname).(ename, dname, location);

na serwer s2 (koszt: [0..680]B). Rezultat tego zapytania przesyłany jest następnie na stronę

klienta. Składa się on z kolekcji struktur złożonych z trzech referencji (koszt jednej: 60B).

Biorąc pod uwagę liczność wyliczoną dla sygnatury korzenia tego zapytania, optymalizator

może wyliczyć koszt przesłania tego rezultatu jako [0..10 * 0..1000 * 60]B = [0..600000]B.

Łącznie zatem koszt wykonania tego scenariusza wynosi [0..2 * 680 + 600000]B =

[0..601360]B. Biorąc jednak pod uwagę to, iż do realizacji tego scenariusza klient musi

komunikować się z serwerami tylko dwa razy, jest to scenariusz znacznie wydajniejszy niż

poprzedni.

3. Wysłanie na serwer s1 zapytania w formie

(department join X

where $s1_1 = dname).($s1_2, dname, location);

gdzie X oznacza rezultat wykonania na serwerze s1 zapytania

(employee groupas $s2_0)

join

103

Page 104: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

$s2_0.(ename groupas $s1_1,

ename groupas $s1_2);

Rezultat tego zapytania składa się z kolekcji struktur, których pierwsze pole jest referencją do

obiektu employee (20B), drugie pole jest wartością ename poddaną dereferencji (8B), trzecie

pole jest referencją do obiektu dname (20B). Koszt przesłania tego rezultatu z serwera s1 na

stronę klienta wynosi [0..1000 * 48]B = [0..48000]B. Ten sam rezultat musi zostać następnie

wysłany razem z zapytaniem

(department join X

where ename = dname).(ename, dname, location);

na serwer s1 (koszt: [0..48000]B). Rezultat tego zapytania przesyłany jest następnie na stronę

klienta. Składa się on z kolekcji struktur złożonych z trzech referencji (koszt jednej: 60B).

Biorąc pod uwagę liczność wyliczoną dla sygnatury korzenia tego zapytania, optymalizator

może wyliczyć koszt przesłania tego rezultatu jako [0..10 * 0..1000 * 60]B = [0..600000]B.

Łącznie zatem koszt wykonania tego scenariusza wynosi [0..2 * 480000 + 600000]B =

[0..1080000]B. Biorąc jednak pod uwagę to, iż do realizacji tego scenariusza klient musi

komunikować się z serwerami tylko dwa razy, jest to scenariusz znacznie wydajniejszy niż

scenariusz pierwszy. Jest on jednak gorszy niż scenariusz drugi, dlatego nie powinien zostać

wybrany przez optymalizator.

Ewaluacja zoptymalizowanych zapytań

Po wybraniu najlepszego scenariusza wykonania zapytania, optymalizator przekształca pierwotne

drzewo składniowe do formy przystosowanej do ewaluacji. W nowym drzewie składniowym

podzapytania wywodzące się od połączania bazodanowego zastępowane są węzłami ermtsq (od

execute remote subquery). Oprócz nazwy połączenia bazodanowego jest on dodatkowo

udekorowany treścią zapytania mającego trafić na zdalny serwer. Zapytanie to zbudowane jest

w specjalny sposób z podzapytania głównego oraz z podzapytań od niego zależnych. Rezultaty

każdego podzapytania będącego elementem tego zapytania powiązane są ze sobą za pomocą

operatorów groupas oraz operatora konstrukcji struktury (,). Nazwy używane przez groupas są

kolejnymi liczbami porządkowymi rozszerzonymi o nazwę połączenia. Struktura zapytania

wygląda następująco:

(zapytanie_glowne groupas $polaczenie_0)join $polaczenie_0.(zapytanie_zalezne1 groupas $polaczenie_1, zapytanie_zalezne2 groupas $polaczenie_2, ...);

104

Page 105: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Dla zapytania użytego w analizowanym przykładzie, będzie to zatem

(department groupas $polaczenie_0)join $polaczenie_0.(dname groupas $polaczenie_1, dname groupas $polaczenie_2, location groupas $polaczenie_3);

w przypadku gdy założymy, że dane o departamentach powinny zostać wysłane na serwer s2 razem

z pierwotnym zapytaniem, oraz

(employee groupas $polaczenie_0)join $polaczenie_0.(ename groupas $polaczenie_1, ename groupas $polaczenie_2);

jeśli okaże się że wysłanie listy pracowników na serwer s1 będzie korzystniejszą operacją.

Drugą modyfikacją w AST jest zastąpienie wszystkich zapytań zależnych za pomocą nazw

odpowiadających kolejnym parametrom operatora groupas w opisanym wyżej schemacie.

Kolejne modyfikacje dotyczą mechanizmu ewaluacji zapytań. Do zbioru rezultatów zapytań R

wprowadzamy nowy rodzaj rezultatu, który nazwywamy rezutlatem złożonym. Jest to specjalny

rodzaj struktury, przezroczystej dla większości operacji języka zapytań. Typowe operacje działając

na rezultacie złożonym w rzeczywistości operują na pierwszym polu tej struktury. Operacja nested

jest natomiast przeciążona w taki sposób, iż działając na rezultacie złożonym, operacja nested

wywoływana jest rekurencyjnie dla wszystkich za wyjątkiem pierwszego pól reprezentującej ją

struktury. W ten sposób na stosie środowiskowym dostępne będą rezultaty zapytań do których

odwołują się nazwy zastępujące zapytania zależne.

Optymalizowanie dostępu do perspektyw Ważnym warunkiem sprawnego działania wirtualnego repozytorium w zaproponowanej przez nas

architekturze jest wydajne funkcjonowanie perspektyw integracyjnych i kontrybucyjnych. Ogólna

idea optymalizacji wykorzystania aktualizowalnych perspektyw została przedstawiona w [53].

W największym skrócie polega ona przepisaniu zapytania odwołującego się do perspekywy

w następujacy sposób:

1. Zamianie nazwy odwołującej się do obiektów udostępnianych przez perspektywę poprzez

zapytanie wyznaczające ziarna tej perspektywy. Dotyczy to tylko takich sytuacji, gdy operacja

virtual objects składa się wyłącznie z intrukcji return. W podobny sposób zamieniany jest

operator deref (wstawiany automatycznie przez kompilator w czasie kontroli statycznej)

105

Page 106: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

poprzez zapytanie podane w on retrieve. Podobnie jak w poprzednim przypadku, jeśli

on retrieve składa się z bardziej złożonego kodu, niż instrukcja return, wówczas optymalizacja

ta nie może zostać zastosowana. Podobnie optymalizowane są instrukcje delete (operacja on

delete) oraz insert (operacja on insert).

2. Zoptymalizowaniu tak otrzymanego zapytania za pomocą technik opisanych w [7], czyli

przeniesienie selekcji przed złączenie, wyciągnięcie niezależnego podzapytania przed operator

niealgebraiczny, wyszukanie martwych podzapytań, zastosowanie indeksów, etc. Następnie

zastosowane mogą zostać techniki przedstawione w niniejszym rozdziale.

Dzięki możliwościom udostępnianym przez perspektywy SBA w dziedzinie definiowania operacji

generycznych, możliwe są również pewne operacje optymalizacyjne implementowane bezpośrednio

przez programistę. Przykładowo, następująca definicja operacji virtual objects (po wprowadzeniu

do języka operatora ping) pozwala na odwołanie się do tego serwera, który w danym momencie jest

najmniej obciążony:

...virtual objects PracSzef : p(ref Prac) [0..*] { if (ping s1 < ping s2) return s1.Prac as p; else return s2.Prac as p;}...

PodsumowanieZagadanienie optymalizacji zapytań jest kluczowym problemem przy budowie języków zapytań.

Nie inaczej jest w przypadku zapytań rozproszonych. Opóźnienia implikowane przez sieć

komputerową uniemożliwiają naiwną (bez optymalizacji) ewaluację takich zapytań.

W rozdziale przedstawiona została propozycja podejścia do optymalizacji rozproszonych zapytań

SBQL. Omówiona została technika dekorowania węzłów drzewa składniowego za pomocą nazw

serwerów, kilka reguł przekształcających zapytania do wydajniejszej w ewaluacji formy, jak

i technika optymalizacji poprzez przesyłanie na serwery częściowo wyewaluowanych zapytań.

Problem optymalizacji w takim środowisku jest olbrzymim tematem, godnym osobnej pracy

doktorskiej. Podstawowe techniki, jakie zostały opisane w niniejszym rozdziale są zaledwie

wierzchołkiem góry lodowej. Niewątpliwie potrzebne są dalsze badania w tej dziedzinie.

106

Page 107: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdział 7:Integracja danych rozproszonych

Wirtualne repozytoriumWirtualnym repozytorium nazywamy w niniejszej pracy zbiór rozproszonych, powiązanych ze sobą

baz danych widocznych dla globalnego użytkownika jako pojedyncza, wirtualna baza danych.

Zgodnie z regułami stworzonymi dla federacyjnych baz danych, wirtualne repozytorium składa się

z szeregu autonomicznych, być może należących do odrębnych organizacji systemów.

Istnieje szereg różnorodnych sytuacji biznesowych dla których pojedyncza organizacja, lub grupa

organizacji (konsorcjum) może podjąć decyzję o stworzeniu wirtualnego repozytorium. Przykładem

może być pewna grupa przedsiębiorstw kolejowych postanawiająca stworzyć wspólny system

informacyjny dotyczący rozkładów jazdy pociągów. System taki umożliwiałby pasażerom

planowanie podróży w oparciu o globalną bazę danych wszystkich istniejących połączeń, dostępną

w jednym miejscu, niezależnie od przedsiębiorstwa obsługującego daną linię. Generalnie można

powiedzieć, że wirtualne repozytorium jest tym bardziej potrzebne, im bardziej niezbędna jest

możliwość przeszukiwania danych geograficznie rozproszonych wg niestandardowych (trudnych do

przewidzenia przez projektantów aplikacji) kryteriów.

Modelowanie wirtualnego repozytoriumStworzenie wirtualnego repozytorium musi wiązać się z uprzednim zaprojektowaniem

odpowiednich reguł dostępu do danych, obowiązujących wszystkie organizacje biorące udział

107

Page 108: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

w konsorcjum tworzącym wirtualne repozytorium. Musi się to wiązać m.in. z decyzjami

związanymi z ustaleniami w zakresie:

• schematu danych jaki musi być przestrzegany przez systemy kontrybuujące do repozytorium,

• jednolitego formatu danych dostarczanych dla repozytorium (daty, waluty, etc),

• reguł dostępu i bezpieczeństwa do lokalnych danych.

Zadaniem każdej z organizaji członkowskiej danego konsorcjum jest zatem przede wszystkim:

• wybranie pewnego zbioru danych lokalnych jakie powinny być udostępnione globalnie,

• wirtualne dostosowanie części lub całości schematu lokalnego do postaci globalnej,

• wirtualne przekonwerowanie lokalnych danych do postaci przyjętej w całym repozytorium.

Węzły integracyjne i kontrybucyjneFizyczne przekształcenia danych niezbędne do dostosowania ich do postaci akceptowalnej

w ramach wirtualnego repozytorium zwykle nie jest możliwe, m.in. ze względu na potencjalną

utratę spójności między danymi i istniejącymi aplikacjami. Przekształcanie danych do wymaganej

postaci musi zatem być realizowane w sposób wirtualny, tzn. przezroczysty dla użytkownika

realizującego zapytanie i przy zachowaniu autonomii lokalnych systemów. Z tego powodu

w federacyjnych bazach danych dostosowywaniem formatu i schematu danych do globalnej postaci

zajmują się zwykle perspektywy.

W proponowanej przez nas architekturze mechanizm perspektywy stosowany jest po po stronie

integrowanych systemów (gdzie pełni rolę osłony/mediatora) oraz po stronie serwera

integracyjnego (gdzie pełni rolę mechanizmu unifikującego dane z integrowanych serwerów).

Zgodnie z tymi założeniami, w architekturze wirtualnej bazy danych można wydzielić dwa rodzaje

węzłów: węzły kontrybucyjne oraz węzły integracyjne.

Węzły kontrybucyjne mają za zadanie udostępnienie lokalnych danych w taki sposób, by mogły

być one wykorzystane przez węzły integracyjne. Węzły te muszą posiadać zdolność dynamicznego

odwzorowania danych lokalnych do postaci dopuszczalnej dla danych globalnych i odwrotnie.

Węzły integracyjne mają za zadanie zapewnić wirtualny, globalny obraz rozproszonej bazy danych

poprzez zebranie danych z integrowanych przez nie węzłów kontrybucyjnych, oraz udostępnienie

ich klientom.

108

Page 109: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Ponieważ węzły integracyjne same mogą pełnić rolę kontrybucyjną w stosunku do innych węzłów

integracyjnych, dlatego możliwe są bardzo różne opcje konfiguracyjne wirtualnej bazy danych -

gwiaździste, drzewiaste, sieciowe, i in. Struktura takiej bazy danych może mieć charakter statyczny

oraz dynamiczny. W pierwszym przypadku na etapie projektowania repozytorium dokładnie

wiadomo jakie węzły będą brały udział w federacji. W drugim przypadku brak jest takiej wiedzy -

węzły mogą się podłączać do repozytorium i odłączać od niego (sytuacja podobna do sieci P2P).

Rys. 13: Przykładowe struktury wirtualnej bazy danych

Architektura wirtualnej bazy danych do zaimplementowania funkcjonalność węzłów

kontrybucyjnych oraz węzłów integracyjnych opiera się na mechanizmie aktualizowalnych

perspektyw SBA. Do zaimplementowania węzła kontrybucyjnego używamy zatem perspektywy

(zwanej przez nas kontrybucyjną) pełniącej rolę osłony/mediatora. Najważniejszym elementem

węzła integracyjnego jest z kolei perspektywa (zwana przez nas integracyjną), której zadaniem jest

zebranie danych ze wszystkich integrowanych węzłów oraz przedstawienie ich w postaci dostępnej

dla globalnego użytkownika. Po raz kolejny pozwolimy sobie w tym miejscu wyraźnie podkreślić,

iż wykorzystanie perspektyw SBA pozwala nam zapewnić kompletną przezroczystość wszelkich

operacji realizowanych na obiektach wirutalnych. Jest to jedna z podstawowych cech

odróżniających nasze rozwiązanie od istniejących federacyjnych baz danych.

Przykładowy scenariuszW dalszej części rozdziału zaprezentujemy prosty przykład ilustrujący konstrukcję, a następnie

funkcjonowanie wirtualnego repozytorium kontrolowanego przez system Odra. W przykładzie

posługujemy się scenariuszem rozproszonej bazy danych połączeń kolejowych. Baza danych

budowana jest przez konsorcjum europejskich przedsiębiorstw kolejowych. System ma umożliwić

łatwe planowanie podróży klientom przemieszczającym się pomiędzy krajami Unii Europejskiej.

109

Page 110: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Dla uproszczenia, załóżmy że integrowane mają być systemy dwóch przedsiębiorstw kolejowych:

system A oraz system B.

Poniższy rysunek przedstawia strukturę modułów stworzonej przez nas przykładowej aplikacji.

schedules

pkp.app.public db.apps.pub

testapp

db.schedule.timetablepkp.app.connections

Warstwa kliencka

Warstwa serwera integracyjnego

Warstwa serwerów kontrybucyjnych

System AW systemie A dane dotyczące połączeń przechowywane są w module Connections, którego

struktura zgodna jest z przedstawionym niżej schematem.

Connections

from : stringto : stringduration : integerprice : integer

Connection

d : integerm : integer

Date

h : integerm : integer

Time

depart_date

depart_time

Moduł ten utworzony został poprzez wprowadzenie do bazy danych kodu źródłowego definicji

modułu pkp.app.connections, którego listing przedstawiono w dodatku B.

110

Page 111: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

System BW systemie B dane dotyczące połączeń przechowywane są w module TimeTable, a jego struktura

zgodna jest z przedstawionym niżej schematem.

TimeTable

name : stringcountry : string

Location

dep_hour : integerdep_minutes : integerduration : integerprice : integer

Link

from

to

Moduł ten utworzony został poprzez wprowadzenie do bazy danych kodu źródłowego definicji

modułu db.schedule.TimeTable. Jego listing również przedstawiono w dodatku B.

Serwer integracyjnyW celu zintegrowania systemów A i B konsorcjum podjęło decyzję, iż każdy z członków musi

spełnić następujące warunki:

1. Administrator zarządzający serwerem integracyjnym otrzyma od administratorów systemów

lokalnych następujące informacje: adres sieciowy komputera, numer portu nasłuchu, nazwa

użytkownika i jego hasło, nazwa modułu w którym przechowywane są dane mające zostać

upublicznione w wirtualnej bazie danych.

2. Dane na temat wszystkich połączeń kolejowych muszą być zgodne ze schematem

przedstawionym na rysunku poniżej.

3. Wszystkie ceny biletów muszą zostać wyrażone w EUR.

Po otrzymaniu potrzebnych danych, administrator serwera integracyjnego tworzy moduł schedules,

w którym umieszcza definicje połączeń bazodanowych prowadzących do serwerów

kontrybucyjnych oraz definicję perspektywy integracyjnej.

111

Page 112: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Schedules

from : stringto : stringduration : integerprice : integerhour : integermin : integerday : integermonth : integer

Connection

Połączenia bazodanowe do poszczególnych serwerów zdefiniowane są następująco:

dblink systema pkp.app.public/[email protected]:8888; dblink systemb db.apps.pub/[email protected]:7777;

Pierwsze ze zdefiniowanych połączeń prowadzi do serwera alfa.pkp.com.pl, posiadającego moduł

pkp.app.public, zawierający dane zgodne z przyjętym schematem kontrybucyjnym. Drugie

połączenie bazodanowe prowadzi do serwera beta.db.de, w którym z kolei dane integracyjne

przechowywane są w module db.apps.pub.

Oprócz tego, na bazie połączeń systema i systemb zdefiniowane jest połączenie grupowe systemab:

Połączenie systemab wykorzystywane jest przez perspektywę integracyjną do zdefiniowania

operacji virtual objects. Zrealizowane jest to w następujący sposób:

virtual objects connections : con(ref systemsab.connections) [0..*] { return systemsab.connections as con; }

Pełny kod źródłowy modułu serwera integracyjnego przedstawiono w dodatku B.

Perspektywa kontrybucyjna systemów A i BAdministrator systemu A musi dostosować dane przechowywane w swoim systemie do postaci

wymaganej przez serwer integracyjny. W tym celu tworzy nowy nowy moduł zawierający

perspektywę kontrybucyjną. Podobna sytuacja dotyczy administratora systemu B. Kod źródłowy

stworzonych przez nich modułów umieszczono w dodatku B.

Wykonywanie zapytańW niniejszym punkcie objaśnimy w jaki sposób ewaluowane są zapytania realizowane na

wirtualnej bazie danych. W tym celu zbudowana została prosta aplikacja kliencka (jej kod źródłowy

umieszczony został w dodatku B), której najważniejszym elementem z naszego punktu widzenia

jest następująca instrukcja:

112

Page 113: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

print db.connections where from = “Katowice” and to = “Warszawa”;

Podczas kompilacji zapytanie będące parametrem instrukcji print dekorowane jest zgodnie

z algorytmem przedstawionym w rozdziale 6. Kompilator wstawia również operację dereferencji

(wymuszoną przez = i print) oraz usuwa odwołanie do nazwy db (pod którą zarejestrowany

w aplikacji klienckiej pod nazwą db). Dzięki temu podczas czasu wykonania na serwer integracyjny

trafia następujące zapytanie:

deref connections where deref from = “Katowice” and deref to = “Warszawa”;

Zapytanie to następnie jest kompilowane i wykonywane przez serwer integracyjny. W normalnym

przypadku związanie nazwy connections powoduje wywołanie operacji virtual objects

perspektywy connections_view. Ponieważ jednak kod tej procedury składa się wyłącznie z jednego

zapytania, dlatego może zostać zastosowana metoda optymalizacji wykorzystania perspektywy

poprzez zamianę nazwy connections na zapytanie będące parametrem return [53]. Podobna

sytuacja dotyczy nazw from i to - zostają zamienione na zapytania pobrane z procedur virtual

objects odpowiadających im podperspektyw. Po zamianie zapytanie to przyjmie następującą

postać:

deref systemsab.connections as con where deref con.from as v = “Katowice” and deref con.to as v = “Warszawa”;

W kolejnym kroku podobna operacja stosowana jest do wystąpień operatora deref. Parametry tego

operatora rozszerzane są o zapytania pobierane z procedur on retrieve poszczególnych

podperspektyw. Zapytania te wstawiane są w drzewie składniowym między operator deref,

a istniejącą wcześniej częścią zapytania. Po zrealizowaniu tej operacji zapytanie przyjmie zatem

następującą postać:

deref (systemsab.connections as con where deref (con.from as v).v = “Katowice” and deref (con.to as v).v = “Warszawa”).con;

Ze względu na własność zbiorowych połączeń bazodanowych opisanych wcześniej, po wykryciu

w zapytaniu nazwy systemsab, kompilator zamienia ją na na nazwy reprezentowanych przez nie

połączeń bazodanowych. Zapytanie przekształcane jest zatem do następującej postaci:

deref (systema.connections as con where deref (con.from as v).v = “Katowice” and deref (con.to as v).v = “Warszawa”).con;unionderef (systemb.connections as con where deref (con.from as v).v = “Katowice” and deref (con.to as v).v = “Warszawa”).con;

113

Page 114: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Takie zapytanie może zostać następnie poddane optymalizacji przez przepisywanie.

W szczególności, po wykryciu niepotrzebnych nazw pomocniczych zapytanie może być

przekształcone do następującej formy:

deref systema.connections where deref from = “Katowice” and deref to = “Warszawa”union deref systemb.connections where deref from = “Katowice” and deref to = “Warszawa”;

Ostatecznie, zapytanie jest dekorowane nazwami serwerów, po czym lewe podzapytanie operatora

union trafia do wykonania na serwer zarejestrowany jako systema, a prawe podzapytanie - na

serwer systemb. Przed wysłaniem usuwane jest odniesienie do nazw połączeń bazodanowych

serwera integracyjnego.

Rozpatrzmy teraz jakie operacje wykonywane są po stronie systemu serwera. Do systemu trafia

następujące zapytanie:

deref connections where deref from = “Katowice” and deref to = “Warszawa”;

Kompilator rozpoznaje nazwę connections jako odwołującą się do perspektywy, po czym zastępuje

ją zapytaniem pobranym z instrukcji return operacaji virtual objects. Podobna operacja

realizowana jest dla każdej pozostałej nazwy występującej w zapytaniu:

deref connection as con where deref con.from as v = “Katowice” and deref con.to as v = “Warszawa”;

Również każda operacja dereferencji rozszerzana jest o operacje pobrane z on retrieve

odpowiednich perspektyw. W naszym przykładzie po wykonaniu tych operacji zapytanie przyjmie

następującą formę:

deref connection as con where deref (con.from as v).v = “Katowice” and deref (con.to as v).v = “Warszawa”).con.( from, to, duration, pln_2_eur(price), depart_time.hour, depart_time.min, depart_date.day, depart_date.month );

Po usunięciu niepotrzebnych nazw pomocniczych przez optymalizator, końcowe zapytanie wygląda

następująco:

deref (connection where deref from = “Katowice” and deref to = “Warszawa”).( from,

114

Page 115: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

to, duration, pln_2_eur(price), depart_time.hour, depart_time.min, depart_date.day, depart_date.month );

Zapytanie to ewaluowane jest na rzeczywistych danych, po czym jego rezultat wraca na serwer

integracyjny. Serwer integracyjny scala go z rezultatem zwróconym przez serwerb, a otrzymany

wynik przesyła do klienta.

Wykonywanie operacji aktualizacyjnychW niniejszym punkcie przeanalizujemy sposób wykonywania operacji aktualizacyjnych

realizowanych na obiektach wirtualnych. Objaśnimy działanie instrukcji delete, przyjmując iż

pozostałe operacje aktualizacyjne ewaluowane są w podobny sposób.

Instrukcja delete kierowana jest na serwer integracyjny, który musi przekazać odpowiednie

polecenia do serwerów kontrybucyjnych. Serwery kontrybucyjne muszą przekształcić instrukcję

realizowaną na danych wirtualnych w taki sposób, by mogła być ona wykonana na danych

rzeczywistych.

Zgodnie z podstawowymi regułami składniowo-semantycznymi dotyczącymi perspektyw SBA

i opisanymi w [53], operacja delete realizowana na perspektywie jest zabroniona jeśli

w perspektywie nie została zdefiniowana operacja on delete. Do zapewnienia możliwości usuwania

obiektów wirtualnych (a co za tym idzie - obiektów rzeczywistych) kod perspektywy integracyjnej

oraz perspektyw kontrybucyjnych wzbogacamy następującym fragmentem:

on delete { delete con;}

Załóżmy teraz, że klient globalnego repozytorium podaje następującą instrukcję:

delete db.connections where deref price < 100;

Po udekorowaniu i usunięciu fragmentu db. zapytanie to wysyłane jest na serwer integracyjny.

Po stronie tego serwera nazwa connections zamieniana jest na odwołanie do połączenia

bazodanowego systemsab (zgodnie z procedurą virtual objects). Oprócz tego, argument operatora

deref rozszerzany jest o zapytanie pobrane w procedury on retrieve podperspektywy price_view.

Po zrealizowaniu tych przekształceń zapytanie przyjmie następującą formę:

delete systemsab.connections as con where deref (con.price as v).v < 100;

115

Page 116: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

po rozwinięciu grupowego połączenia bazodanowego i usunięciu niepotrzebnej nazwy

pomocniczej:

delete systema.connections as con union systemb.connections as con where deref con.price < 100;

Zgodnie z semantyką perspektyw SBA dla każdego wirtualnego obiektu wykonany musi zostać kod

podany w procedurze on delete. Podobnie jak w przypadku procedury on retrieve, kod tej

procedury podatny jest na pewne optymalizacje. Optymalizacje nie są możliwe jeśli kod procedury

on delete składa się z więcej niż jednej instrukcji. W takim przypadku operacja on delete jest

wywoływana osobno dla każdego rezultatu zapytania będącego parametrem operacji delete.

Jeśli natomiast ciało procedury on delete składa się z pojedynczej instrukcji delete q1, wówczas

instrukcja delete q2 wykonywana na perspektywie może być przekształcona do postaci delete q1.q2.

W naszym przykładzie zapytanie może zostać przepisane do następującej postaci:

delete ((systema.connections as con union systemb.connections as con) where deref con.price < 100).con;

a następnie (dzięki właściom operatorów union i where) przekształcone do dwóch instrukcji

delete:

delete (systema.connections as con where deref con.price < 100).con;delete (systemb.connections as con where deref con.price < 100).con;

Takie instrukcje mogą zostać udekorowane połączeniami bazodanowymi (następnie usuwanymi),

po czym wysłane do wykonania na odpowiednie serwery. Na serwer trafi zatem zapytanie

delete (connections as con where deref con.price < 100).con;

a serwer systemb zapytanie

delete (connections as con where deref con.price < 100).con;

Po stronie serwera systema nazwa connections zastępowana jest zapytaniem pobranym z procedury

virtual objects:

delete (connection as con as con where deref con.price < 100).con;

a zapytanie będące parametrem operacji delete rozszerzone o zapytanie z instrukcji delete podanej

w on delete:

delete (connection as con as con where deref con.price < 100).con.con;

PodsumowanieW rozdziale umówiliśmy mechanizm integracji danych oparty na aktualizowalnych perspektywach

SBQL. Zaprezentowaliśmy prosty przykład integracji, oraz wyjaśniliśmy jak przebiega wymiana

116

Page 117: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

danych między węzłami systemu rozproszonego w przypadku zapytań oraz operacji

aktualizacyjnych.

117

Page 118: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp
Page 119: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Rozdział 8:Prototyp

WprowadzenieW niniejszym rozdziale przedstawimy najważniejsze informacje dotyczące implementacji prototypu

narzędzia o zaproponowanej przez nas architekturze. Prototyp ten oraz badania przeprowadzone

przy jego użyciu są głównymi produktami niniejszej pracy doktorskiej. Podkreślamy tutaj wyraźnie,

że wszelkie prace badawcze w dziedzinie zaawansowanych środowisk programistycznych nie

poparte działającym prototypem są niewiarygodne. Ze względu na ogromną liczbę czynników

wpływających na spójność, kompletność i efektywność takiego środowiska nie jest możliwa

jakakolwiek teoria dająca niepodważalne odpowiedzi na wiele żywotnych pytań.

Omawiany system jest w pełni funkcjonalny i działa z prototypową, rozproszoną bazą danych oraz

ze zintegrowanym językiem zapytań rozszerzonym do kompletnego języka programowania. System

jest napisany w języku Java, oraz rozwijany jest obecnie w ramach osobnych podprojektów na

potrzeby europejskich projektów eGovBus oraz VIDE. Ze względu na ograniczenia objętościowe

niniejszej pracy opisane zostały jedynie najważniejsze decyzje implementacyjne. Szczegółowy opis

znajduje się w dokumentacji technicznej systemu Odra.

Baza danych i instancja bazy danychW systemie Odra wprowadzono rozróżnienie znane z niektórych SZRBD pomiędzy bazą

danych i jej instancją [5].

119

Page 120: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Baza danych ma charakter statyczny, jest zbiorem struktur (“składem danych”) przechowujących

dane zorganizowane w określony sposób. Baza danych w systemie Odra może mieć charakter

trwały lub nietrwały. W pierwszym przypadku dane przechowywane są w pliku systemu

operacyjnego, a w drugim - w pamięci operacyjnej.

Instancja bazy danych jest z zbiorem procesów operujących na tej bazie danych. Obecnie

zaimplementowane są (jako wątki Javy) dwa procesy:

• Proces komunikacji sieciowej (LSNR).

Proces ten odpowiedzialny jest za nasłuchiwanie na połączenia nadchodzące od klientów oraz

realizowanie póżniejszej komunikacji. Komunikacja zaimplementowana jest za pomocą

technologii Java NIO [100, 102, 103].

• Proces serwera (SVRP).

W momencie gdy proces LSNR zarejestruje nadchodzące połączenie, tworzony jest nowy proces

SVRP reprezentujący klienta po stronie serwera i realizujący w jego imieniu polecenia przesyłane

przez sieć. Każdy proces SVRP posiada swój prywatny skład danych nietrwałych (przeznaczony

na przechowywanie obiektów lokalnych, sesyjnych, itp.), jak również korzysta ze składu

globalnego, współdzielonego z innymi procesami SVRP (właściwa baza danych). Także niektóre

moduły systemu (np. kompilator i interpreter SBQL) są prywatne dla każdej sesji.

Architektura systemuNa rysunku poniżej przedstawiono architekturę systemu Odra. W systemie tym można wyróżnić

następujące elementy:

• Programy klienckie (np. interfejs linii poleceń)

Programy klienckie korzystają z biblioteki implementującej niskopoziomowy protokół

komunikacyjny systemu Odra. Biblioteka ta pozwala na komunikację za pomocą interfejsu

poziomu wywołań.

• Analizator składniowy SBQL

Moduł przekształca kod źródłowy SBQL na abstrakcyjne drzewo składniowe.

• Analizator kontekstowy SBQL

Moduł odpowiedzialny za statyczną ewaluację programów. Głównym celem analizy kontekstowej

jest kontrola typów oraz wykrycie odwołań do niezadeklarowanych nazw. Z wyników analizy

120

Page 121: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

kontekstowej (np. informacji na temat numeru sekcji, w której związana została nazwa)

korzystają moduły optymalizatora oraz generatora kodu pośredniego.

• Optymalizator zapytań SBQL

Zadaniem optymalizatora jest przekształcenie zapytań w równoważną semantycznie formę,

ale wydajniej ewaluowaną.

• Generator kodu

Moduł odpowiedzialny za przekształcenie drzewa składniowego do bajtowego kodu pośredniego.

• Menedżer uprawnień

Moduł odpowiedzialny za mechanizmy bezpieczeństwa. Wykorzystywany podczas logowania

użytkownika do systemu oraz podczas kompilacji programów.

• Kompilator modułów

Moduł odpowiedzialny za budowę struktur reprezentujących w bazie danych moduły.

• Program ładujący/konsolidator

Moduł odpowiedzialny za zastępowanie logicznych odniesień w kodzie pośrednim na fizyczne

adresy obiektów. Głównie dotyczy to wywołań procedur.

• Bufor procedur

Kod skonsolidowanych procedury umieszczany jest buforze procedur. Bufor procedur przyspiesza

działanie programu konsolidatora.

• Interpreter programów SBQL

Moduł odpowiedzialny za wykonywanie programów SBQL zapisanych w kodzie bajtowym.

• Menedżer modułów

Moduł odpowiedzialny za zarządzaniem wnętrzem modułów, np. tworzeniem i usuwaniem

procedur.

• Moduły

Moduł jest jednostką organizacji bazy danych/aplikacji. Struktura ta zostanie omówiona w dalszej

części niniejszego rozdziału.

• Dane czasu wykonania

Dane dostępne dla interpretera.

121

Page 122: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• Metadane

Dane dostępne dla kompilatora.

• Menadżer obiektów trwałych

Moduł odpowiadający za operacje realizowane na danych trwałych (zapisywanych na dysku).

Tłumaczy operacje wyrażone w kontekście modelu M0 na ciągi bajtów (i owrotnie).

• Menedżer obiektów nietrwałych

Moduł odpowiadający za operacje realizowane na danych nietrwałych (przechowywanych

w pamięci operacyjnej).

• Menedżer transakcji

Moduł odpowiedzialny za przetwarzanie transakcji. Transakcje w systemie Odra posługują się

blokadami na poziomie stron. Mechanizm transakcji jest przedmiotem osobnego podprojektu,

dlatego nie został opisany w niniejszej pracy.

• Koder/dekoder rezultatów

Moduł pozwalający na przekształcanie struktur reprezentujących rezultaty zapytań na postać

łatwą do przesłania przez sieć (i owrotnie).

• Koder/dekoder metadanych

Moduł pozwalający na przeksztalcanie fragmentów bazy danych reprezentujących metadane na

postać łatwą do przesłania przez sieć. Metabaza przesyłana jest między systemami Odra w celu

realizacji statycznej kontroli typów zapytań rozproszonych.

Modularna organizacja bazy danychZgodnie z naszą koncepcją przedstawioną w rozdziale 4, podstawową jednostką organizacyjną bazy

danych jest moduł. Moduł w systemie Odra przechowuje zarówno dane czasu wykonania (baza

danych), jak i dane czasu kompilacji (metabaza). Dotyczy to zarówno obiektów reprezentujących

byty programistyczne, jak i obiektów bazy danych.

Pierwszym (podłączonym do obiektu root) obiektem każdej bazy danych jest moduł o nazwie sys.

Moduł ten jest automatycznie importowany przez wszystkie inne moduły bazy danych. Oprócz

tego, iż moduł ten stanowi korzeń hierarchii modułów, jest również miejscem przechowywania

danych pełniących rolę biblioteki standardowej SBQL. Dodatkowo, w module tym przechowywane

są dane pełnieniące rolę katalogu bazy danych. Niemal wszystkie operacje tworzące, usuwające

i modyfikujące obiekty warstwy bazy danych zorganizowane są w taki sposób, iż automatycznie

122

Page 123: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

wstawiają dane do struktur utworzonych w tym module. Przykładowo, dodanie do systemu

procedury w jakimkolwiek module, powoduje automatyczne utworzenie wystąpienia odpowiedniej

zmiennej opisującej tę procedurę w katalogu bazy danych. Użytkownik może następnie użyć

zapytania SBQL, aby uzyskać listę wszystkich procedur zdefiniowanych w systemie, a także

podstawowe informacje na ich temat. Innym rodzajem informacji przechowywanym w katalogu

bazy danych jest lista kont użytkowników zdefiniowanych w systemie, wraz z ich hasłami

(zaszyfrowanymi), oraz innymi elementarnymi informacjami systemowymi. Katalog bazy danych

pełni zatem funkcję zbioru metadanych dotyczących bazy danych i przeznaczonych dla programisty

systemu Odra.

CLI, SBQL IDE, Java, ...

analizator sk!adniowy SBQL

sie"

analizator kontekstowy

optymalizator

kompilator modu!ów

AST

modu!u

AST zapytania

ad-hoc

kod #ród!owy

SBQL

generator kodu

AST

procedury

kod po$redni

procedury

menad%er obiektówtrwa!ych

interpreter

modu! !aduj&cy/konsolidator

bufor procedur

mened%er transakcji

mened%er uprawnie'

menad%er modu!ów

modu!ymodu!

modu!

dane czasu wykonania

procedury

perrspektywy

wyst&pienia zmiennych

klasy

po!&czenia bazodanowe

indeksy

metadane

procedury

perrspektywy

deklaracje zmiennych

klasy

po!&czenia bazodanowe

indeksy

definicje

typów

operatory

i typy

wbudowane

menad%er obiektów

nietrwa!ych

koder rezultatów

dekoder rezultatów

sie"

koder/dekoder rezultatów

koder/dekoder metadanych

odra odra odra

Rys. 14: Architektura systemu Odra

Bezpośrednio do modułu sys podłączane są moduły reprezentujące schematy bazy danych

poszczególnych użytkowników. Każde konto użytkownika utworzone w bazie danych posiada taki

globalny moduł. Wszystkie dane utworzone wewnątrz tego modułu (w tym podmoduły) należą do

123

Page 124: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

odpowiadającego mu użytkownika, który może w ich ramach tworzyć struktury bazy danych, takie

jak procedury, perspektywy, deklarować zmienne, jak i instancjonować je.

Poniższy rysunek przedstawia koncepcyjny, przykładowy stan bazy danych. Baza danych zawiera

dwa moduły użytkowników raist i scott. Moduły te zawierają podobiekty reprezentujące inne

moduły, klasy, indeksy, perspektywy, procedury globalne, obiekty czasu wykonania będące

wystąpieniami zmiennych, itd. Obiekty emp i dept to instancje klas Employee i Department.

hr

Department

emp_ename_idx

employ

emp_avg_sal_view

Employee

raist

scott

emp

emp

dept

emp

dept

public

public

employ

sys

Rys. 15: Przykładowe drzewo bazy danych

Skład danychSkład danych jest mechanizmem organizującym podstawowe struktury bazy danych na dysku lub

w pamięci operacyjnej. Istnieją dwa rodzaje składów danych: nietrwały i trwały. Pierwszy z nich

jest typowy dla języków programowania, gdzie występuje pod nazwą “sterta”. Trwały skład danych

z reguły występuje w bazach danych. Zawartość trwałego składu danych nie ulega utracie po

wyłączeniu komputera, jest współdzielona z innymi sesjami. Architektura składu danych

w systemie Odra zainspirowana została przez podobną strukturę systemu Loqis [30, 31, 92].

124

Page 125: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

W przeciwieństwie do tradycyjnych, dyskowych SZBD, system Odra nie posiada specjalnych

struktur danych ani algorytmów wspierających optymalne wykorzystanie dysków twardych

komputerów. Zamiast tego, system przystosowany jest do intensywnego wykorzystania możliwie

największych fragmentów dostępnej pamięci operacyjnej. System zakłada, iż cała lub przynajmniej

większa część bazy danych znajduje się w pamięci operacyjnej. Trwałość zapewniana jest przez

mechanizm znany pod nazwą memory mapped files. Mechanizm ten wykorzystuje funkcjonalność

struktur systemu operacyjnego odpowiedzialnych za działanie pamięci wirtualnej, zwalniając nas

z konieczności implementowania mechanizmów I/O oraz buforowania. System operacyjny

automatycznie ładuje potrzebne dane do pamięci operacyjnej oraz zapisuje je na dysku. Dla baz

danych wielkości do kilkuset megabajtów jest to mechanizm sprawdzający się dostatecznie dobrze,

by mógł stać się bazą prototypu, jakim jest Odra.

Warstwa obiektów bazy danych i metabazy

(moduły, procedury, klasy, perspektywy, linki bazodanowe, etc.)

Warstwa obiektów składu danych

(obiekty proste, złożone, referencyjne)

Warstwa fizyczna składu danych

(pliki, pamięć, bloki danych)

Rys. 16: Warstwowa struktura bazy danych

Implementacja składu danych podzielona została na trzy warstwy. Najbardziej podstawową jest

warstwa fizyczna, implementująca mechanizmy zarządzania wolną przestrzenią w ramach plików

danych. Bazująca na tej implementacji warstwa obiektów składu danych implementuje podstawową

funkcjonalność zgodną z modelem danych danych SBA znanym pod nazwą M0. Warstwa obiektów

składu danych jest z kolei podstawą warstwy obiektów bazy danych. Jej zadaniem jest wyrażenie

modeli danych wyższych niż M0 w terminach modelu M0. Interpreter SBQL korzysta z warstwy

najbardziej szczytowej.

Trwały skład danych przechowywany jest w tzw. pliku danych. Plik ten montowany jest w systemie

Odra jako plik mapowany w pamięci, co oznacza że jego zawartość widziana jest dla systemu jako

jedna, wielka tablica bajtów. Wszystkie operacje I/O na tym pliku realizowane są przez system

operacyjny, bez udziału systemu Odra.

125

Page 126: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Niezależnie od tego czy pracujemy z trwałym, czy nietrwałym składem danych, fizycznie jest on

widziany wewnątrz systemu jako tablica bajtów Javy. Aby w obszarze tym można było zapisywać,

potrzebne są mechanizmy zarządzania wolną przestrzenią. Mechanizmy te dostępne są dla warstwy

obiektów bazy danych jako metody malloc() i free(). Podobnie jak w języku C, metoda malloc()

pobiera argument w postaci wielkości obszaru jaki ma być zarezerwowany, a zwraca liczbę będącą

pozycją w tablicy bajtów (adresem) określającym początek zarezerwowanego obszaru. Brak

dostatecznej ilości wolnej pamięci sygnalizowany jest wyjątkiem. Metoda free() pobiera adres

zwrócony przez malloc(), i zwalnia wskazywany przez niego obszar.

Zarówno w trwałym, jak i nietrwałym składzie danych pamięć zarządzana jest w taki sam sposób.

Odpowiedzialny jest za to nieco zmodyfikowany, choć wciąż bardzo prosty algorytm, znany pod

nazwą sequential-fit. Algorytm ten zakłada, iż pamięć dzieli się na szereg bloków pamięci

połączonych w listę dwukierunkową. Każdy węzeł takiej listy składa się z następujących

elementów: stan (0 - wolny, 1 - zajęty), adres poprzedniego węzła (0 jeśli brak), adres następnego

węzła (rozmiar sterty + 1 jeśli brak kolejnego węzła), dane.

Na bazie warstwy fizycznej zbudowana została warstwa zarządzająca podstawowymi operacjami na

najważniejszych rodzajach obiektów wywodzących się z podejścia stosowego. Każdy obiekt jest

strukturą następującej postaci:

rodzaj(1 bajt)

nazwa (4 bajty)

obiekt nadrzędny (4 bajty)

referencje zwrotne(4 bajty)

wartość(4 bajty)

Aby utworzyć obiekt w bazie danych, warstwa obiektów składu danych rezerwuje 17 bajtów

w bazie danych za pomocą malloc(), a następnie zapisuje pod otrzymanym adresem strukturę przedstawioną powyżej.

Obsługiwane są następujące rodzaje obiektów:

• COMPLEX_OBJECT

Obiekty z wartością w postaci ciągu adresów podobiektów. Reprezentują obiekty złożone w modelu M0.

• STRING_OBJECT

Obiekty z wartością w postaci adresu bloku danych zawierającego ciąg znaków i jego długość,

• INTEGER_OBJECT Obiekty z wartością w postaci liczb typu integer,

126

Page 127: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• DOUBLE_OBJECT

Obiekty z wartością w postaci adresu bloku danych zawierającego liczbę typu double.

• BOOLEAN_OBJECT

Obiekty z wartością w postaci true lub false,

• REFERENCE_OBJECT

Obiekty z wartością w postaci adresu obiektu trwałego (obsługuje wiszące wskaźniki),

• POINTER_OBJECT

Obiekty z wartością w postaci adresu trwałego (brak obsługi wiszących wskaźników),

• BINARY_OBJECT

Obiekty z wartością w postaci wskażnika do bloku zawierającego binarny ciąg znaków i jego

długość,

• AGGREGATE_OBJECT

Obiekty złożone służące do modelowania kolekcji obiektów o tych samych nazwach. Jest to

swoista optymalizacja fizyczna, przyspieszająca wyszukiwanie obiektów o tych samych nazwach.

Pole nazwy obiektu przyjmuje numer będący pozycją w tzw. indeksie nazw (opisanym dalej).

Trzecie pole jest adresem obiektu nadrzędnego COMPLEX_OBJECT lub AGGREGATE_OBJECT.

Pole referencji zwrotnych jest adresem bloku pamięci przechowującym zbiór adresów obiektów

REFERENCE_OBJECT wskazujących na dany obiekt (mających jego adres jako wartość).

Ostatnie pole może przyjąć jedną z dwóch form:

• jest wartością samą w sobie (INTEGER_OBJECT, BOOLEAN_OBJECT,

REFERENCE_OBJECT, POINTER_OBJECT) jeśli wartość ta zawsze może być zapisana przy

użyciu maksymalnie 4 bajtów,

• jest adresem osobnego bloku pamięci w którym przechowywana jest właściwa wartość obiektu,

być może razem z długością tej wartości (AGGREGATE_OBJECT, COMPLEX_OBJECT,

DOUBLE_OBJECT, STRING_OBJECT, BINARY_OBJECT).

Referencje zwrotne są mechanizmem zapewniającym funkcjonalność automatycznego zarządzania

pamięcią. Trzecim polem każdego obiektu jest referencja do nadmiarowego bloku danych

(o strukturze takiej jak w przypadku obiektów COMPLEX_OBJECT i AGGREGATE_OBJECT)

przechowującego adresy obiektów REFERENCE_OBJECT posiadających adres tego obiektu jako

127

Page 128: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

wartość (czyli wskazujących na niego). Jeśli obiekt nie posiada żadnych referencji zwrotnych,

wówczas wartością tego pola jest 0.

875732845 (warto!")0 (ref. zwrotne)11 (nazwa)9 (REFERENCE_OBJECT)

123 (warto!")322564323 (ref. zwrotne)12 (nazwa)1 (INTEGER_OBJECT)

5233332 (adres 1)1 (ilo!" referencji

zwrotnych)

Obiekt referencyjny

Obiekt wskazywany

Rys. 17: Przykładowy sytuacja pomiędzy obiektem referencyjnym i obiektem wskazywanym

Referencje zwrotne pozwalają nam uniknąć efektu wiszących wskaźników. W momencie gdy

kasowany jest jakiś obiekt, sprawdzane są jego referencje zwrotne, a obiekty

REFERENCE_OBJECT o adresach będących referencjami zwrotnymi są automatycznie usuwane

zanim usunięty zostanie właściwy obiekt. Referencje zwrotne są zawsze aktualne, tzn. każda

operacja usunięcia obiektu REFERENCE_OBJECT powoduje usunięcie odpowiedniego wpisu ze

zbioru referencji obiektu wskazywanego. Podobnie, operacja zmiany wartości takiego obiektu

powoduje usunięcie odpowiedniej referencji zwrotnej z obiektu który był wskazywany przed

aktualizacją, oraz umieszczenie nowej referencji zwrotnej w obiekcie wskazywanym przez

referencję po aktualizacji.

Tworzenie programówObiekty bazy danych mogą być tworzone na dwa sposoby. Pierwszy z nich jest charakterystyczny

dla baz danych i polega na wykorzystaniu poleceń DDL do zdefiniowania odpowiednich struktur.

Programista dysponuje do tego celu narzędziem linii poleceń podobnych do SQL*Plus systemu

Oracle. Utworzenie zatem nowego indeksu polega na wydaniu polecenia create index, dodanie

nowej procedury - create procedure, itd. Wszystkie obiekty muszą być tworzone w ramach

utworzonego wcześniej modułu. Moduły tworzy się za pomocą polecenia create module. Polecenie

to posiada formę bezargumentową i argumentową. Pierwsza forma tworzy pusty moduł.

Argumentem drugiej formy jest pełny kod źródłowy modułu, przypominający kod źródłowy

sformułowany za pomocą typowych języków programowania. Kod źródłowy pełni rolę “skryptu”,

128

Page 129: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

którego przetworzenie przez bazę danych odpowiada kolejnym wywołaniom operacji create

procedure, create class, etc.

Kompilacja aplikacji z poziomu środowiska programistycznego wiąże się z przesłaniem do serwera

bazy danych kodów żródłowych wszystkich modułów, które zostały zmodyfikowane od czasu

ostatniej kompilacji. Serwer bazy danych zawiera kompilator i interpreter programów SBQL.

Każdy przesłany moduł jest zatem parsowany, kontrolowany typologicznie, optymalizowany, po

czym generowane są struktury bazy danych oraz kod wykonywany później przez interpreter.

Poniższy rysunek ilustruje sytuację, gdy do bazy danych trafia polecenie create module, którego

zadaniem jest utworzenie nowego modułu. Parametrami tej operacji jest globalna nazwa modułu

nadrzędnego (w tym przypadku scott) oraz kod źródłowy tego modułu. Po prawej stronie

przedstawione są struktury bazy danych jakie tworzone są po skompilowaniu tego modułu. W bazie

danych utworzone zostaną dwa obiekty reprezentujące wystąpienia zmiennej x, jeden obiekt

reprezentujący procedurę, oraz jeden obiekt reprezentujący indeks założony na zmiennej x.

hr

sayHello

xx

x

sayHello

x_idx

Metabaza(dane czasu kompilacji)

Baza danych(dane czasu wykonania)

Modu! u"ytkownika scott (stworzony automatycznie)

Modu! u"ytkownika raist (stworzony automatycznie)

#rodowisko standardowe i biblioteka standardowa

Modu! aplikacyjny (stworzony przez r$cznie przez u"ytkownika)

scott

raist

test

sys

module hr { x [2..*] : integer; sayHello(name : string) { print “Hello, “ + name; }

index x_idx on x;}

Rys. 18: Baza danych po utworzeniu modułu hr

Jeśli moduł hr istnieje już w bazie danych, wówczas nie jest on usuwany razem ze swoją

zawartością, a jedynie jego struktura dostosowywana jest do postaci zgodnej z przesyłanym kodem

źródłowym.

129

Page 130: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

• Obiekty bazy danych które są zgodne ze swoimi deklaracjami w kodzie źródłowym nie są

modyfikowane.

• Obiekty których deklaracje nie istnieją w kodzie źródłowym są usuwane.

• Obiekty których struktura różni się w stosunku do kodu źródłowego są dostosowywane do nowej

postaci (procedury) lub są usuwane i tworzone na nowo (egzemplarze zmiennych).

Domyślnie obiekty które muszą zostać usunięte z bazy danych kasowane są automatycznie (tryb

force polecenia create module). Istnieje jednak możliwość wyłączenia tego zachowania (tryb

noforce), który w przypadku wykrycia konfliktu między stanem bazy danych oraz przesyłanym

kodem źródłowym zgłasza błąd, a użytkownik musi ręcznie dostosować bazę danych do pożądanej

formy.

hr

sayHelloWorld

x

Metabaza(dane czasu kompilacji)

Baza danych(dane czasu wykonania)

Modu! u"ytkownika scott (stworzony automatycznie)

Modu! u"ytkownika raist (stworzony automatycznie)

#rodowisko standardowe i biblioteka standardowa

Modu! aplikacyjny (stworzony przez r$cznie przez u"ytkownika)

scott

raist

test

sys

module hr { x [2..*] : integer; sayHelloWorld() { print “Hello, world!”; }

index x_idx on x;}

x

x

x_idx

sayHelloWorld

Rys. 19: Baza danych po zmodyfikowaniu modułu hr

Poniższy rysunek ilustruje sytuację która nastąpiła po przedstawionej powyżej. Do bazy danych

trafia zmodyfikowany kod modułu hr. W nowej wersji usunięto procedurę sayHello, natomiast

dodano procedurę sayHelloWorld. Ponieważ pierwsza z tych procedur nie posiada swojego

odpowiednika w kodzie źródłowym, dlatego zostaje usunięta z bazy danych. Pozostałe obiekty

z bazy danych pozostały nietknięte (nie tylko ich struktura, ale również stan). Podobne zmiany

zaszły w metabazie.

130

Page 131: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Konstrukcja, kompilacja i inicjalizacja modułówKonstrukcja modułów jest stosunkowo złożonym procesem, niezbędnym jednak przede wszystkim

do poprawnego zrealizowania statycznej kontroli typów. Informacje wyznaczone podczas tego

procesu wykorzystujemy również do zastąpienia niektórych dynamicznych wiązań wiązaniami

statycznymi (w celu optymalizacji niektórych operacji).

Kod źródłowy modułu trafia do bazy danych, gdzie jest parsowany. Tworzony jest nowy obiekt

bazy danych reprezentujący moduł, a w jego wnętrzu powstają obiekty reprezentujące byty

programistyczne zawarte w kodzie źródłowym (zarówno obiekty czasu wykonania, jak i obiekty

metabazy). Procedury nie są w tym momencie kompilowane, natomiast kod źródłowy każdej

procedury zostaje dopisany do obiektu reprezentującego tę procedurę. W skonstruowanym w ten

sposób module ustawiona zostaje flaga invalid. Flaga ta uniemożliwia korzystanie z modułu. Moduł

musi zostać najpierw skompilowany i zanicjalizowany.

W tym momencie poszczególne moduły aplikacji są od siebie ciągle niezależne. Można dodawać

nowe moduły, jak i usuwać istniejące. Poprawność odwołań do obiektów globalnych w tych

modułach nie jest kontrolowana.

Przed każdą pierwszą próbą skorzystania z zawartości modułu (np. poprzez wywołanie jego

procedury) zrealizowaną w ramach jakiegoś zewnętrznego narzędzia (np. interfejsu linii poleceń

przeznaczonego dla użytkownika), system sprawdza stan flagi invalid. Jeśli jest ona opuszczona,

wówczas następuje interpretacja polecenia przekazanego przez użytkownika. Jeśli flaga jest

ustawiona, wówczas inicjowany jest proces kompilacji.

Kompilacja realizowana jest rekurencyjnie dla każdego modułu importowanego przez

kompilowany moduł. Jeśli któryś z importowanych modułów posiada opuszczoną flagę invalid,

wówczas nie jest kompilowany. Celem procesu kompilacji jest analiza statyczna poszczególnych

bytów programistycznych zawartych w module. Dla każdego takiego bytu realizowany jest proces

statycznej analizy składającej się z kontroli kontekstowej, a dla procedur również optymalizacja

oraz generacja kodu. Statyczny stos środowiskowy potrzebny do analizy statycznej inicjalizowany

jest poprzez umieszczenie w pierwszej sekcji binderów utworzonych na podstawie wszystkich

globalnych elementów kompilowanego modułu. Do takiej sekcji dodawane są następnie bindery

utworzone na podstawie bytów programistycznych zawartych w importowanych modułach. Na tak

zainicjalizowanym stosie realizowana jest statyczna analiza danego bytu.

131

Page 132: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Modyfikacje programówJeśli usuwany moduł posiadał opuszczoną flagę invalid, wówczas dla wszystkich modułów

importujących ten moduł flaga ta jest automatycznie ustawiana. Wymagają one odtąd rekompilacji.

Podobna sytuacja ma miejce jeśli w ramach poprawnego modułu usuwany jest jedynie pojedynczy

byt (np. procedura). Podobna sytuacja ma miejsce w przypadku bardziej drobnoziarnistej ewolucji

schematu. Jeśli skompilowany moduł A odwołuje się (poprzez listę importową) modułu B, oraz byt

ten jest usuwany lub modyfikowany, wówczas moduł A staje się niepoprawny i wymaga ponownej

kompilacji. Problem ten rozwiązaliśmy poprzez utworzenie referencji do każdego modułu który

importuje dany moduł. Jeśli pewien moduł jest modyfikowany, wówczas dzięki takim referencjom

możemy uzyskać listę modułów zależnych od tego modułu. W każdym z tych modułów ustawiana

jest flaga valid na false. Moduł z taką flagą wymaga ponownej kompilacji i konsolidacji z resztą

modułów.

Kod pośredniKażdy program SBQL jest kompilowany do postaci kodu pośredniego. Dotyczy to zarówno

procedur, jak i zapytań ad-hoc. Przykładowo, zapytanie 1 * 2 + 3 może być przekształcone do ciągu

następujących operacji:

ldi 1 ldi 2 muli ldi 3 addi

Kod pośredni jest przed wykonaniem przekształcany do postaci kodu wykonywalnego.

Przekształcenie to polega obecnie na usunięciu wiązania dynamicznego w kilku przypadkach

i zastąpienie go wiązaniem statycznym. W przyszłości istnieje możliwość dalszych optymalizacji

w tym zakresie, łącznie z kompilacją do postaci kodu bajtowego wirtualnej maszyny Javy, czy też

wręcz do kodu maszynowego.

Każda instrukcja kodu bajtowego posiada następującą formę:

kod operacji(4 bajty)

parametr(8 bajtów)

Parametr jest liczbą całkowitą, która w zależności od rodzaju operacji ma inne znaczenie. Na

przykład w przypadku operacji ldi, parametr jest wkładany na stos rezultatów jako liczba całkowita.

132

Page 133: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Z kolei w przypadku ldcs, parametr jest indeksem w tzw. puli stałych, a w przypadku cri jest to

numer pozycji w indeksie nazw.

Pula stałych jest ciągiem bajtów przechowywanym razem z kodem bajtowym. Jej wnętrze stanowi

zbiór wartości mogących potencjalnie przyjmować dowolne długości (więcej niż 8 bajtów).

Przechowywane w niej wartości zazwyczaj pochodzą z kodu źródłowego, gdzie przyjmują postać

literałów.

Indeks nazw jest globalną strukturą stworzoną dla całej bazy danych, przechowującą pary

<identyfikator, nazwa>. Nazwy obiektów pojawiające się w kodzie pośrednim występują jako

liczby całkowite reprezentujące identyfikator.

W kilku kolejnych punktach pokażemy kilka przykładowych przypadków wygenerowanego kodu

pośredniego.

Generowanie kodu dla zapytań

Dla zapytania 1 union 2 generator kodu stworzy następujący kod pośredni:

ldi 1 ; umieszczamy 1 na stosie rezultatow bag ; konwertujemy szczytowy element QRES na bag ldi 2 ; umieszczamy 2 na stosie rezultatow bag ; konwertujemy szczytowy element QRES na bag unn ; zdejmujemy dwa elementy z QRES i realizujemy operacje sumy bagow

Poniżej kod jaki może zostać wynerowany dla zapytania emp.dept:

ldbag ; ladujemy pusty bag przeznaczony na rezultaty czastkowe ldi 0 ; umieszczamy na QRES liczbe 0 stcntr ; inicjalizujemy nia licznik bnd emp ; wiazemy nazwe emp dup ; kopiujemy wynik w celu policzenia jego elementow cnt ; zliczamy ilosc elementów w kolekcji bedacej wynikiem wiazanialoop: dup ; kopiujemy rozmiar elementow kolekcji ; otrzymanej przez zwiazenie emp inccntr ; zwiekszamy licznik o 1 ldcntr ; ladujemy licznik elementów na QRES grei ; sprawdzamy czy licznik jest wiekszy lub rowny rozmiarowi kolekcji brt end ; jesli tak, wowczas konczymy ewaluacje ldcntr ; ladujemy licznik extr ; umieszczamy na stosie element kolekcji o numerze rownym licznikowi crenv ; tworzymy nowa sekcje na stosie srodowiskowym nstd ; wypelniamy nowa sekcje binderami do ; wnetrza analizowanego obiektu bnd dept ; wiazemy nazwe dept dsenv ; usuwamy sekcje stosu ENVS ins2 ; umieszczamy rezultat w kolekcji przeznaczonej na rezultaty czastkowe

133

Page 134: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

bra loop ; przechodzimy do nastepnego elementu empend: pop ; usuwamy rozmiar kolekcji otrzymanej przez zwiazanie emp fltn ; spłaszczamy kolekcje bedaca wynikiem (jesli to mozliwe)

Obsługa modułów

W związku z tym, iż każdy program SBQL musi być wykonany w ramach modułu, w czasie

wykonania stos środowiskowy musi być odpowiednio zainicjalizowany binderami do globalnych

obiektów danego modułu oraz modułów importowanych przez niego. Kod podobny do poniższego

poprzedza kod wygenerowany dla każdego zapytania ad-hoc:

crgenv ; nowa sekcja ENVS nie polaczona linkiem statystycznym ; z sekcja bazowa ldmn “modul” ; ladujemy na stos referencje do modulu “modul” eimpo ; wnetrza modulow importowanych przez modul trafiaja na ENVS ldmn “modul” ; ladujemy na stos referencje do modulu “modul” ldmen ; zaladowanie referencji do korzenia bazy danych modulu nstd ; zrealizowanie operacji nested na korzeniu bazy danych modulu

Generowanie kodu dla procedur

Dla następującej procedury:

divide(x : integer; y : integer) : real { if (y == 0) return -1; else return x / y; }

wygenerowany zostanie następujący kod:

initle: crbnd y ; utworzenie bindera na ENVS na podstawie parametru y crbnd x ; utworzenie bindera na ENVS na podstawie parametru xbody: bnd y ; zwiazanie nazwy y ldi 0 ; zaladowanie wartosci 0 eqi ; sprawdzenie czy y = 0 brf else ; jesli y nie jest rowne 0, skok do etykiety else ldi -1 ; zaladowanie wartosci -1 retv ; zakonczenie dzialania proceduryelse: bnd x ; zwiazanie nazwy x bnd y ; zwiazanie nazwy y divi ; podzielenie x przez y retv ; zakonczenie dzialania procedury

Wołanie procedury realizowane jest za pomocą instrukcji call. Następujące zapytanie:

divide(6; 2);

134

Page 135: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

tłumaczone jest do następującej postaci:

ldi 6 ; zaladowanie na stos wartosci parametru aktualnego ldi 2 ; zaladowanie na stos wartosci parametru aktualnego call ”michal.mod1.divide” ; wywolanie procedury “divide”

Instrukcja call działa jako makro tożsame z następującym ciągiem operacji:

crgenv ; utworzenie nowej sekcji globalnej ldmn “michal.mod1” ; zaladowanie na stos referencji do ; modulu “michal.mod1” eimpo ; wnetrza modulow importowanych ; przez modul na ENVS ldmn “michal.mod1” ; zaladowanie na stos referencji ; do modulu “michal.mod1” ldmen ; zaladowanie referencji do korzenia ; bazy danych modulu nstd ; realizacja operacji nested na korzeniu bazy danych crenv ; utworzenie sekcji lokalnej wywolanej procedury

Następnie wykonywany jest skompilowany kod procedury, ktorej nazwa pobierana jest ze stosu

QRES. Po zakończeniu wykonywania operacji call, automatycznie realizowane są następujące

operacje:

dsenv ; usuniecie szczytowej sekcji ENVS dsenv ; usuniecie szczytowej sekcji ENVS

W związku z tym, iż podczas kompilacji modułu kompilator dysponuje pelnymi informacjami na

temat lokalizacji poszczególnych obiektów bazy danych, istnieje możliwość optymalizacji kodu

bajtowego poprzez usunięcie części wiązań dynamicznych i zastąpieniem ich wiązaniami

statycznymi. Przykładowo, każdą instrukcję ldmn zamienić można na instrukcję alternatywną,

której argumentem jest adres docelowego modułu, a nie jego nazwa. Optymalizacja tego typu nie

będą jednak omawiane w niniejszej pracy.

Reprezentacja obiektów bazy danychW niniejszym punkcie skrótowo opiszemy w jaki sposób zaimplementowano podstawowe byty

programistyczne języka SBQL za pomocą modelu danych M0.

Moduły

Moduł w bazie danych przyjmuje formę obiektu złożonego (COMPLEX_OBJECT) składającego

się z kilku podobiektów systemowych. Obiekty systemowe dla odróżnienia od obiektów

użytkownika (dostępnych dla operacji wiązania) posiadają nazwy poprzedzone znakiem $.

Strukturę modułu przedstawia poniższy rysunek.

135

Page 136: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Korzystamy z następującej notacji: (C) - COMPLEX_OBJECT, (I) - INTEGER_OBJECT,

(B) - BINARY_OBJECT, (S) - STRING_OBJECT, (D) - DOUBLE_OBJECT,

(R) - REFERENCE_OBJECT, (N) - BINARY_OBJECT, (P) - POINTER_OBJECT.

$kind (I)

$name (S)

$invalid (B)

$imports (C)

$refs (C)

$meta (C)

$data (C)

$submodules (C)

nazwa modułu (C)

Obiekt $kind zawiera informację o tym, że cała struktura reprezentuje moduł. Obiekt $name

przechowuje globalną nazwę modułu. Obiekt $invalid wskazuje czy procedury danego modułu

muszą być przekompilowane. Jeśli w strukturze modułu lub kodzie procedur nastąpią jakieś

zmiany, wówczas wartość tego obiektu ustawiana jest na true. Obiekt $imports zawiera podobiekty

typu STRING_OBJECT z wartościami będącymi globalnymi nazwami modułów importowanych

przez moduł bieżący. Obiekt $refs zawiera referencje modułów importujących dany moduł. Obiekt

$meta jest korzeniem metabazy modułu. Obiekt $data jest korzeniem bazy danych modułu. Obiekt

$submodules zawiera moduły podrzędne.

Procedury

Procedury są obiektami przechowującymi skompilowany kod SBQL oraz dane potrzebne do

optymalizowania zapytań w czasie wykonania.

$kind (I)

$ast (C)

$obj (N)

$cst (N)

nazwa procedury (C)

Obiekt $ast posiada podobiekty BINARY_OBJECT z wartościami będącymi zserializowanymi (za

pomocą mechanizmu serializacji Javy) drzewami składniowymi wszystkich bądż tylko niektórych

(decyduje o tym generator kodu) zapytań występujących w procedurze. W czasie wykonania

interpreter może odczytywać i przetwarzać te drzewa, co jest niezbędne do dynamicznej

optymalizacji zapytań. Obiekt $obj zawiera kod bajtowy procedury. Obiekt $cst zawiera listę

136

Page 137: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

wartości (zwykle literałów kodu źródłowego), których długość jest większa od 4B, albo nie daje się

przewidzieć.

Procedury w metabazie służą do opisania nazw i typów parametrów formalnych oraz zwracanej

przez procedurę wartości.

$kind (I)

$mincard (I)

$maxcard (I)

$typenameid (I)

$ref (I)

$args (C)

nazwa procedury (C)

Obiekty $mincard i $maxcard zawierają wartości reprezentujące minimalną i maksymalną liczność

rezulatu procedury. Wartość obiektu $typenameid reprezentuje typ zwracanej przez procedurę

wartości. Wartość obiektu $ef mówi czy rezulat procedury jest obiektem wskaźnikowym (>0) czy

też nie (0). Podobiektami obiektu $args są obiekty reprezentujące parametry formalne procedury

(podane jako struktury reprezentujące deklaracje zmiennych).

Deklaracje zmiennych

Obiekty te reprezentują deklaracje zmiennych, czyli “podpowiadają” modułowi kompilatora

realizującemu operację analizy kontekstowej jakich danych (typ, ilość obiektów, itd.) można

spodziewać się w czasie wykonania w danym środowisku. Występują tylko w metabazie.

$kind (I)

$mincard (I)

$maxcard (I)

$typenameid (I)

$ref (I)

nazwa zmiennej (C)

Obiekty $mincard i $maxcard zawierają wartości reprezentujące minimalną i maksymalną liczność

zmiennej. Wartość obiektu $typenameid reprezentuje typ zmiennej. Wartość obiektu $ref mówi czy

typ zmiennej jest referencyjny (>0) czy też nie (0). Interpretacja tej wartości zależy od systemu

typów.

137

Page 138: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Struktury

Obiekty te opisują pola typów strukturalnych. Ich nazwa nie powinna być dostępna dla wiązania,

dlatego powinna być rozszerzona o przedrostek $. Jeśli potrzebny jest nazwany typ strukturalny, wówczas należy utworzyć strukturę, a następnie wskazać ją jako typ bazowy obiektu

reprezentującego definicję typu. Występują tylko w metabazie.

$kind (I)

$fields (C)

nazwa struktury (C)

Obiekt $fields posiada podobiekty zgodne ze strukturą deklaracji zmiennej. Podobiekty te stanowią

opis poszczególnych pól struktury.

Typy

Obiekty te wprowadzają nowe, nazwane typy danych. Każdy typ posiada nazwę oraz typ bazowy.

Występują tylko w metabazie.

$kind (I)

$ref (I)

nazwa typu (C)

$typenameid (I)

Wartość obiektu $typenameid reprezentuje typ bazowy (np. typ prosty, albo struktura). Wartość

obiektu $ref mówi czy typ zmiennej jest referencyjny (>0) czy też nie (0).

Operatory binarne

Obiekty te reprezentują proste, arytmetyczne operatory binarne, których operandami są wartości

typu prostego. Tworzone są automatycznie podczas operacji tworzenia bazy danych w metabazie

modułu sys, jako część środowiska standardowego SBQL.

Wartość obiektu $terminal jest ciągiem znaków reprezentującym tekstową formę operatora.

W czasie kontroli typów nazwa ta stanie się nazwą bindera wkładanego do sekcji bazowej

statycznego ENVS. Obiekt $restype jest wskaźnikiem na obiekt deklaracji prostego typu danych,

określającego typ wartości zwracanej po zastosowaniu operatora. Obiekt $ltype jest wskażnikiem

na obiekt deklarujący prosty typ danych dopuszczalny dla lewego operandu, a obiekt $rtype -

prawego. Obiekt $lcrc jest wskażnikiem na obiekt deklarujący prosty typ danych, określający typ

do którego musi nastąpić koercja lewego operandu aby możliwe było zastosowanie operatora.

138

Page 139: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Obiekt $rcrc ma takie samo znaczenie, ale w stosunku do prawego operandu. Obiekt $opcode jest

kodem operacji kodu pośredniego reprezentującego dany operator.

$kind (I)

$terminal (S)

$restype (P)

$ltype (P)

$rcrc (P)

$rtype (P)

$lcrc (P)

$opcode (I)

nazwa operatora (C)

Operatory unarne

Obiekty te reprezentują proste operatory unarne, których operandami są wartości typu prostego.

Tworzone są automatycznie podczas operacji tworzenia bazy danych w metabazie modułu sys, jako

część środowiska standardowego SBQL.

$kind (I)

$terminal (S)

$restype (P)

$argtype (P)

$opcode (I)

nazwa operatora (C)

Wartość obiektu $terminal jest ciągiem znaków reprezentującym tekstową formę operatora.

W czasie kontroli typów nazwa ta stanie się nazwą bindera wkładanego na stos. Obiekt $restype jest

wskażnikiem na obiekt MBPrimitiveType określający typ wartości zwracanej po zastosowaniu

operatora. Obiekt $argtype jest wskażnikiem na obiekt MBPrimitiveType określającym

dopuszczalny typ operandu. Obiekt $opcode jest kodem operacji kodu pośredniego

reprezentującego dany operator.

Typy proste

Obiekty te reprezentują typy proste wbudowane w język SBQL i tworzone są automatycznie

podczas operacji tworzenia bazy danych w metabazie modułu sys jako część środowiska

standardowego.

139

Page 140: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

$kind (I)

$typeid (I)

nazwa typu (C)

Wartość obiektu $typeid oznacza specyficzny numer oznaczający wbudowany typ prosty (1 -

integer, 2 - real, itd.).

Interfejs użytkownikaSystem Odra wyposażony jest w dwa narzędzia administracyjne. Pierwsze z nich jest interfejsem

linii poleceń o nazwie Odra CLI (Odra Command-Line Interface). Narzędzie to pozwala

w interaktywny sposób wprowadzać instrukcje i zapytania języka SBQL, a także obserwować

wyniki ich działania. Oprócz tego, dostępne są w nim polecenia administracyjne umożliwiające np.

zatrzymanie serwera bazy danych. Specjalna grupa instrukcji create/drop pozwala tworzyć i usuwać

obiekty bazy danych.

Rys. 20: Narzędzia administracyjne systemu Odra

W drzewie obiektów bazy danych przechodzi się w podobny sposób, jak w narzędziach linii

poleceń systemów operacyjnych. Przykładowo, polecenie cm (od change module) pozwala na

zmianę bieżącego modułu, a polecenie ls (od list) wyświetla listę obiektów metabazy bieżącego

modułu.

140

Page 141: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Oprócz tego, zbudowane zostało przez nas również drugie narzędzie, którego zadaniem jest

realizacja podstawowych operacji administracyjno-programistycznych w środowisku graficznym.

Okno nawigatora przedstawia hierarchiczną strukturę bazy danych, okno edytora kodu pozwala

wprowadzać kod źródłowy modułów.

Rys. 21: Narzędzia administracyjne systemu Odra

PodsumowanieW rozdziale omówiliśmy szczegóły techniczne związane z funkcjonowaniem prototypowego

systemu Odra. Omówiliśmy architekturę systemu, organizację modularną bazy danych, kod

pośredni oraz przyjęty przez nas sposób reprezentowania różnorodnych bytów programistycznych

języka SBQL w ramach bazy danych. Rozdział zakończyliśmy prezentując proste narzędzia

administracyjno-programistyczne jakie zostały stworzone na potrzeby systemu.

141

Page 142: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp
Page 143: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Podsumowanie pracy

W pracy zaprezentowaliśmy wizję nowoczesnego narzędzia programistycznego przeznaczonego do

tworzenia obiektowych baz danych i ich aplikacji w środowisku rozproszonym oraz

scentralizowanym. Przedstawiliśmy naszą opinię mówiącą o tym, iż każda próba rozszerzenia

języka programowania takiego jak Java o obsługę baz danych skazana jest z góry na klęskę.

W rzeczywistości satysfakcjonujący stan integracji języków programowania z bazami danych może

być osiągnięty jedynie poprzez zaprojektowanie nowej klasy języków programowania, traktujących

kolekcje jako możliwe rezultaty wyrażeń (traktowanych jako zapytania) i dostarczających

operatorów umożliwiających makroskopowe przetwarzanie takich danych. Naszym zdaniem język

taki powinien również zostać rozszerzony o specjalne konstrukcje zapewniające komunikację

między aplikacjami pracującymi w środowisku rozproszonym. Okazuje się bowiem, iż

przetwarzanie danych masowych za pomocą tradycyjnego middleware prowadzi do niepotrzebnych

komplikacji owocujących niestabilnością oprogramowania oraz jego niską wydajnością. Naszym

zdaniem problemy te może zniwelować język zapytań oraz middleware w postaci systemu

zarządzania rozproszoną bazą danych.

Jako dowód koncepcji będących wynikiem badawczym niniejszej pracy, zbudowaliśmy system

Odra - prototypowy system zarządzania bazą danych wyposażony w obiektowy język

programowania zintegrowany z konstrukcjami programistycznymi. W ramach pracy doktorskiej nie

jest możliwe zbudowanie kompletnego narzędzia tego typu, gdyż jest to zadanie dla bardzo dużego

zespołu dysponującego budżetem. Dlatego poprzestaliśmy jedynie na kluczowych zagadnieniach.

Niezbędne są dalsze prace koncypcyjne oraz implementacyjne zmierzające do wyposażenia

143

Page 144: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

systemu w wiele niezbędnych mechanizmów, np. transakcji, czy bezpieczeństwa. Prace te będą

kontynuowane w ramach projektów VIDE oraz eGovBus, realizowanych przez PJWSTK.

144

Page 145: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Dodatek A: Przykładowy program SBQL

Poniżej przedstawiamy przykładowy prosty, samodzielny program SBQL. Jest to implementacja

popularnego schematu pracownik-dział, znanego zwłaszcza z systemów relacyjnych. W obecnej

postaci aplikacja ta ma charakter scentralizowany, a interfejsem użytkownika jest konsola.

Wykorzystując komponenty GUI przygotowane dla systemu Odra w ramach osobnego projektu,

aplikacja może zostać rozszerzona o graficzny interfejs użytkownika. Innym scenariuszem

wykorzystania jest wykorzystanie tradycyjnego scenariusza klient-serwer i wykorzystanie JDBC do

podłączenia aplikacji napisanej w języku Java.

module firma { type tpracownik is record { imie : string; nazwisko : string; stanowisko : string; pensja : integer; pracuje : ref dzial; }

type tdzial is record { nazwa : string; lokalizacja : string; zatrudnia : ref prac [0..*]; }

prac : tpracownik [0..*];

145

Page 146: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

dzial : tdzial [0..*];

inicjalizacja() { d1 : ref dzial := create ( “Sprzedaz” as nazwa, “Warszawa” as lokalizacja ) as dzial;

d2 : ref dzial := create ( “Badania” as nazwa, “Warszawa” as lokalizacja ) as dzial;

d3 : ref dzial := create ( "Produkcja” as nazwa, “Poznan” as lokalizacja ) as dzial;

p1 : ref prac := create ( “Jan” as imie, “Kowalski” as nazwisko, “Programista” as stanowisko, 14000 as pensja, d3 as pracuje ) as prac;

p2 : ref prac := create ( “Jozef” as imie, “Mlynarski” as nazwisko, “Programista” as stanowisko, 12000 as pensja, d2 as pracuje ) as prac;

p3 : ref prac := create ( “Grzegorz” as imie, “Lubczyk” as nazwisko, “Sprzedawca” as stanowisko, 850 as pensja, d1 as pracuje ) as prac;

p4 : ref prac := create ( “Stefan” as imie,

146

Page 147: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

“Nowak” as nazwisko, “Sprzedawca” as stanowisko, 800 as pensja, d1 as pracuje ) as prac;

d1.(create p4 as zatrudnia); d1.(create p3 as zatrudnia); d2.(create p2 as zatrudnia); d3.(create p1 as zatrudnia); }

main() { // wyszukanie wszystkich pracownikow zarabiajacych > 100 print prac where pensja > 100;

// drugi, trzeci, piąty pracownik pod wzgledem najlepiej zarabiajacych print (prac orderby pensja desc).(bag 2, 3, 5);

// pracownicy zatrudnieni w dziale Sprzedaz print (dzial where nazwa = “Sprzedaz”).zatrudnia.prac;

// departamenty w ktorych nie pracuje zaden programista print dept where not exists (zatrudnia.prac where stanowisko = “Programista”); }

}

Page 148: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

148

Page 149: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Dodatek B:Kod źródłowy zintegrowanegosystemu połączeń kolejowych

Kod źródłowy modułu pkp.app.connections (system A)module connections { type conntype is record { from : string; to : string; duration : integer; price : integer; depart_date : record { d : integer; m : integer; } depart_time : record { h : integer; m : integer; } }

connection : conntype [0..*];}

Kod źródłowy modułu db.schedule.timetable (system B)module timetable { type linktype is record { dep_hour : integer; dep_minutes : integer; duration : integer; price : integer; from : ref location; to : ref location; }

149

Page 150: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

type locationtype is record { name : string; country : string; }

link : linktype [0..*]; location : loctype [0..*];}

Perspektywa kontrybucyjna systemu Amodule public { import pkp.app.connections;

type connection_type is record { from : string; to : string; duration : integer; price : integer; hour : integer; min : integer; day : integer; month : integer; }

pln_2_eur(pln : integer) : integer { // wywołanie zewnetrznej uslugi posiadajacej dostep do aktualnego kursu walut // i przeliczenie za jego pomoca sumy w PLN do EUR }

view connections_view { virtual objects connections : con(ref connection) [0..*] { return connection as con; }

on retrieve : connection_type { return connection.( from, to, duration, pln_2_eur(price), depart_time.hour, depart_time.min, depart_date.day, depart_date.month); }

view from_view { virtual objects from : v(ref connection.from) { return con.from as v; }

150

Page 151: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

on retrieve : string { return v; } }

view to_view { virtual objects to : v(ref connection.to) { return con.to as v; }

on retrieve : string { return v; } }

// podobnie dla pozostalych pol typu conn_type // ...

view price_view { virtual objects price : v(ref connection.price) { return con.price as v; }

on retrieve : string { return pln_2_eur(v); } }

view hour_view { virtual objects hour : v(ref connection.depart_time.h) { return con.depart_time.h as v; }

on retrieve : string { return v; } }

// podobnie dla pozostalych pol typu conn_type // ... }}

Perspektywa kontrybucyjna systemu Bmodule pub { import odra.time; import db.schedule.timetable;

type connection_type is record { from : string; to : string;

Page 152: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

duration : integer; price : integer; hour : integer; min : integer; day : integer; month : integer; }

view connections_view { virtual objects connections : link(ref link) [0..*] { return link as link; }

on retrieve : connection_type { return link.( from.location.name, to.location.name, duration, price, dep_hour, dep_min, get_current_day_of_month(), // implementacja w odra.time get_current_month()); // implementacja w odra.time }

view from_view { virtual objects from : v(ref link.from.name) { return link.from.location.name as v; }

on retrieve : string { return v; } }

view to_view { virtual objects to : v(ref link.to.name) { return link.to.location.name as v; }

on retrieve : string { return v; } }

// podobnie dla pozostalych pol typu conn_type // ...

view price_view { virtual objects price : v(ref link.price) { return link.price as v; }

152

Page 153: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

on retrieve : string { return v; } }

view hour_view { virtual objects hour : v(ref link.dep_hour) { return link.dep_hour as v; }

on retrieve : string { return v; } }

// podobnie dla pozostalych pol typu conn_type // ... }}

Perspektywa integracyjnamodule schedules { dblink systema pkp.app.public/[email protected]:8888; dblink systemb db.apps.pub/[email protected]:7777; dblink systemsab using systema, systemb;

type conn_type is record { from : string; to : string; duration : integer; price : integer; hour : integer; min : integer; day : integer; month : integer; }

view connections_view { virtual objects connections : con(ref systemsab.connection) [0..*] { return systemsab.connections as con; }

on retrieve : conn_type { return con; }

view from_view { virtual objects from : v(ref con.from) { return con.from as v; }

Page 154: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

on retrieve : string { return v; } }

view to_view { virtual objects to : v(ref con.to) { return con.to as v; }

on retrieve : string { return v; } }

view duration_view { virtual objects duration : v(ref con.duration) { return con.duration as v; }

on retrieve : string { return v; } }

// podobnie dla pozostalych pol typu conn_type // ... }}

Aplikacja klienckamodule testapp { dblink db schedules/[email protected]:8888;

main() { print db.connections where from = “Katowice” and to = “Warszawa”; }}

154

Page 155: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Dodatek C:Ewaluacja przykładowego zapytania SBQL

Poniżej przedstawiamy poszczególne kroki ewaluacji prostego zapytania zgodnego

z przedstawionymi wyżej założeniami. Zapytaniem tym jest Employee where Name = “J. Smith” and

salary > 10000. Zapytanie to powinno zwrócić identyfikatory wewnętrzne (referencje) wszystkich

obiektów bazy danych reprezentujących pracowników zarabiających więcej niż 10000. W naszym

przykładzie zapytanie to wykonywane jest dla bazy danych przedstawionej poniżej:

<i0, entry, <i1, Employee, <i4, Name, “J. Smith”> <i5, Salary, 65000> > <i2, Employee, <i6, Name, “S. Bush”> <i7, Salary, 45000> > <i3, Department, <i8, Name, “Sales”> <i9, Location, “London”> >>

155

Page 156: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Employee(i1), Employee(i2), Department(i3)

1. Initialize ENVS and QRES

2. Execute bind Employee

3. Pop one element from QRES

5. Execute bind Name

Employee(i1), Employee(i2), Department(i3)

Employee(i1), Employee(i2), Department(i3)

Name(i4), Salary(i5)

Employee(i1), Employee(i2), Department(i3)

6. Push "J. Smith"

Employee(i1), Employee(i2), Department(i3)

Name(i4), Salary(i5)

7. Pop two elements, dereference i4, compare "J. Smith", and "J. Smith", push true

Employee(i1), Employee(i2), Department(i3)

Name(i4), Salary(i5)

8. Execute bind "Salary"

Employee(i1), Employee(i2), Department(i3)

Name(i4), Salary(i5)

9. Push 10000

Employee(i1), Employee(i2), Department(i3)

Name(i4), Salary(i5)

10. Pop two elements, dereference i4, compare "J. Smith", and "J. Smith", push true

Employee(i1), Employee(i2), Department(i3)

Name(i4), Salary(i5)

11. Pop two elements, dereference i4, compare them, push true

Employee(i1), Employee(i2), Department(i3)

4. Create a new ENVS section. Execute nested i1

Employee(i1), Employee(i2), Department(i3)

Name(i4), Salary(i5)

12. Pop one element, since the value is true, add i1 to eres. Remove one section from ENVS.

Employee(i1), Employee(i2), Department(i3)

14. Execute bind Name

Employee(i1), Employee(i2), Department(i3)

Name(i6), Salary(i7)

15. Push "J. Smith"

Employee(i1), Employee(i2), Department(i3)

Name(i6), Salary(i7)

16. Pop two elements, dereference i6, compare "S. Bush", and "J. Smith", push false

Employee(i1), Employee(i2), Department(i3)

Name(i6), Salary(i7)

17. Execute bind Salary

Employee(i1), Employee(i2), Department(i3)

Name(i6), Salary(i7)

18. Push 10000

Employee(i1), Employee(i2), Department(i3)

Name(i6), Salary(i7)

19. Pop two elements, dereference i7, compare 10000 and 45000, push true

Employee(i1), Employee(i2), Department(i3)

Name(i6), Salary(i7)

20. Pop two elements, compare them, push false

Employee(i1), Employee(i2), Department(i3)

13. Create a new ENVS section. Execute nested i2

Employee(i1), Employee(i2), Department(i3)

Name(i6), Salary(i7)

21. Pop one element, since the value is false, do not add i2 to eres. Remove one section from ENVS.

Employee(i1), Employee(i2), Department(i3)

bag(i1, i2)

i4

i4

"J. Smith"

true

true

i5

true

i5

10000

true

true

true

i6

false

i6

"J. Smith"

false

i7

false

i7

10000

false

true

false

22. Push eres onto QRES

Employee(i1), Employee(i2), Department(i3) i1

156

Page 157: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Dodatek D:Przetwarzanie danych XML za pomocą SBQL

Język XML [18] stał się standardem zapisu i wymiany informacji w Internecie. Dotyczy to

zwłaszcza narzędzi przeznaczonych do integracji danych i aplikacji. Przykładowo, w niektórych

systemach ESB (Enterprise Service Bus), XML wykorzystywany jest m.in. do budowy

komunikatów przenoszonych następnie pomiędzy usługami sieci Web, gdzie są analizowane,

przekształcane i wysyłane dalej. Operacje te realizowane są przy współudziale dodatkowych

języków (np. XSLT, XMLSchema, XQuery i in.) i programowane w typowych językach niskiego

poziomu (np. C#) lub językach skryptowych (np. JavaScript).

Jako iż SBA od samego początku swego istnienia zaprojektowane zostało m.in. do obsługi danych

półstrukturalnych, naturalna jest zatem próba zastosowania języka SBQL do przetwarzania danych

XML. Dotyczy to zarówno operacji związanych z językiem zapytań, jak i statycznej kontroli typów,

transformacji danych i in. Zadanie to jest o tyle łatwe, iż model danych M0 w podejściu stosowym

bardzo przypomina model danych XML.

SBA może zostać wykorzystane do stworzenia języka dostosowanego składniowo do XML,

podobnego np. do XQuery [19]. Podejście zaprezentowane w niniejszej pracy (oraz kilku

wcześniejszych prototypów zbudowanych przez autora) jest jednak inne. Celem było osiągnięcie

157

Page 158: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

takiej sytuacji, by na danych XML można było pracować za pomocą dokładnie takich samych

konstrukcji, jakich używamy do operowania na “zwykłych” danych. Dążymy do tego, aby XML

widoczny był jedynie na wejściu (import) oraz na wyjściu (export, wyświetlanie rezultatów

zapytań) systemu Odra. Po zaimportowaniu dokumentu XML, zawarte w nim dane nie różnią się

wewnętrznie od typowych danych systemu Odra. Choć SBQL może działać na danych

półstrukturalnych bez wiedzy dostępnej podczas kompilacji na temat ich struktury, my zakładamy

iż każdy przetwarzany dokument posiada odpowiadającą mu definicję typu.

Import dokumentu XML polega na wskazaniu pliku z danymi oraz zadeklarowaniu zmiennej, na

którą przypisany zostanie rezultat zwrócony z modułu importującego te dane. Istnieje również

możliwość automatycznego wygenerowania odpowiedniego typu danych poprzez odzwierciedlenie

danych ze wskazanego schematu XML na definicje typów SBQL (zostało to zrealizowane

w ramach osobnego podprojektu).

Przyjęto następującą formę odwzorowania modelu danych XML na model M0:

• każdy element XML jest obiektem złożonym w sensie modelu M0,

• każdy atrybut elementu XML jest reprezentowany jako obiekt prosty, którego nazwa poprzedzona

jest znakiem @,

• każdy węzeł tekstowy jest reprezentowany jako obiekt prosty, którego nazwa poprzedzona jest

znakiem #.

Znaki @ i # nie mają żadnej semantyki dla kompilatora zapytań. Nie są to operatory, a jedynie

zwykłe znaki będące częścią nazwy obiektu. Interpretowane są one wyłącznie przez moduły

generujące dokumenty XML na podstawie zawartości bazy danych/rezultatów zapytań.

Powyższe założenia nie wspierają oczywiście bezpośrednio bardziej zaawansowanych konstrukcji

XML, np. przestrzeni nazw, encji, sekcji CDATA, i in. Wprowadzenie takich konstrukcji nie wydaje

się jednak zadaniem specjalnie złożonym.

Jako przykład rozpatrzmy następujący dokument:

<a> b <c d=”xxx”>e</c> f <g>aaa</g></a>

Taki dokument wyrażony może być w składzie danych za pomocą następującego zbioru obiektów:

158

Page 159: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

<i0, “a”, <i1, “#text1”, “b”> <i2, “c”, <i5, “@d”, “xxx”> <i6, “#text”, “e”> > <i3, “#text2”, “f”> <i4, “g”, <i7, “#text”, “aaa”> >>

W zewnętrznym systemie typów typ reprezentujący ten dokument można zadeklarować

w następujący sposób:

type doctype is record { #text1 : string; c : record { @d : string; #text : string; } #text2 : string; g : #text(string);}

Pozwolimy sobie w tym miejscu zaznaczyć, iż dereferencja wartości nazwanej nazwą pomocniczą

zwraca dokładnie taki sam rezultat jak dereferencja struktury z pojedynczym polem. Oznacza to, że

poniższe deklaracje są całkowicie równoważne:

zmienna1 : record { pole : integer; } zmienna2 : pole(integer);

Wartość będąca rezultatem dereferencji obiektu typu doctype o stanie odpowiadającym

przedstawionemu wyżej dokumentowi przyjmie następującą postać:

a(struct { #text1(“b”), c(struct { @d(“xxx”), #text(“e”) }), #text2(“f”), g(#text(“aaa”)) }

Dokładnie taką samą wartość można uzyskać formułując zapytanie przy użyciu literałów oraz kilku

typowych operatorów. Rezultat takiego zapytania może być przekazany do procedury, podany jako

prawa strona operatora podstawiania, itp. Przykładowo, w następujący sposób zadeklarować można

zmienną doc typu doctype, utworzyć jej nowy egzemplarz oraz przypisać mu odpowiednią wartość:

159

Page 160: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

doc : doctype [0..*];create (“b” as #text1, (“xxx” as @d, “e” as #text) as c, “f” as #text2, “aaa” as #text as g) as a as doc;

Realizując operację odwrotną, dowolny wynik zapytania można w łatwy sposób zamienić na tekst

zgodny składniowo z XML.

Poprzez kombinację opisanych wyżej cech razem z operatorami pomocniczej nazwy as i groupas

łatwo również można przekształcić jeden dokument w inny. Przypomnijmy, że operator as

wprowadza nazwę pomocniczą dla każdej wartości kolekcji będącej jego argumentem. Operator

groupas działa podobnie, ale nazwę pomocniczą wprowadza dla całego rezultatu niezależnie od

jego rodzaju. Oznacza to zatem, iż przykładowo:

(bag 1, 2, 3) as x zwraca bag { x(1), x(2), x(3) }, czyli

<x>1</x><x>2</x><x>3</x>

(bag 1, 2, 3) groupas x zwraca x(bag { 1, 2, 3 }), czyli

<x> 1 2 3</x>

Ze względu na “płaską” strukturę plików XML, zarówno pola struktur, jak i elementy kolekcji

wyświetlane są w dokumentach XML w podobny sposób. Oznacza to, że podobnie jak

w powyższym przykładzie, również rezultat poniższego zapytania w postaci XML jest podobny:

(1, 2, 3) as x zwraca x(struct { 1, 2, 3 }), czyli

<x> 1 2 3</x>

Rozpatrzmy teraz następujący dokument wejściowy:

<books> <book> <title>Ogniem i mieczem</itle> <author_first>Henryk</author_first> <author_last>Sienkiewicz</author_last> <isbn>434-3235-3323</isbn>

160

Page 161: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

</book> <book> <title>Lalka</itle> <author_first>Boleslaw</author_first> <author_last>Prus</author_last> <isbn>433-3235-3213</isbn> </books> </books>

Dokument taki może zostać zaimporowany do bazy danych z zewnętrznego źródła. Jeśli podany

zostanie dodatkowo schemat XML, wówczas obok obiektów reprezentujących listę książek, na jego

podstawie utworzone mogą być również odpowiednie typy oraz zmienne. Jeśli obiekt

reprezentujący daną zmienną zostanie poddany dereferencji, wówczas jego wynik tożsamy będzie

z wynikiem następującego zapytania:

( (“Ogniem i mieczem” as #text as title, “Henryk” as #text as author_first, “Sienkiewicz” as #text as auhor_last, “434-3235-3323” as #text as isbn) as book union (“Lalka” as #text as title, “Boleslaw” as #text as author_first, “Prus” as #text as author_last, “433-3235-3213” as #text as isbn) as book ) groupas books;

Aby przekształcić ten rezultat do poniższej postaci (typowe zastosowanie XSLT):

<html> <head> <title>Lista ksiazek</title> </head> <body> ksiazka: <book>“Ogniem i mieczem”</book>,↵ autor: <author>Henryk Sienkiewicz</author><br/> ksiazka: <book>“Lalka”</book>,↵ autor: <author>Boleslaw Prus</author><br/> </body> </html>

wystarczy następujące zapytanie:

books.( “Lista ksiazek” as #text as title as head, (book.(“ksiazka: \”“ as #some_text1, title.#text as #title as book, “\”, autor: “ as #some_text2, (author_first.#text + “ “ + author_last.#text) as #text as author),

161

Page 162: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

“” as br) groupas body) ) as html;

Przekształcenia takie można realizować także w formie bardziej typowych programów SBQL.

Poniższy program realizuje tę samą operację co przedstawione wyżej zapytanie. Dostępna jest tutaj

pełna moc obliczeniowa SBQL.

module trans_test { // typ reprezentujacy dokument wejsciowy type input_doc is record { books : book(input_book) [0..*]; }

// typ reprezentujacy ksiazke w dokumencie wejsciowym type input_book is record { title : #text(string); author_first : #text(string); author_last : #text(string); isbn : #text(string); }

// typ represzentujacy dokument wyjsciowy type output_doc is { html : record { head : record { title : string := “Lista ksiazek”; }

body : record { book : output_book [0..*]; } } }

// typ reprezentujacy ksiazke w dokumencie wyjsciowym type output_book is { #intro : string; book : #text(string); #writtenby : string; author : #text(string); br : string; }

// przeksztalcenie ksiazki z dokumentu wejsciowego // do ksiazki z dokumentu wyjsciowego transform_book( book : input_book ) : output_book { return book.( “ksiazka: \”“ as #text as intro, title.#text as book, “\”, autor: “ as #text as writtenby, (author_first.#text + “ “ + author_last.#text) as author);

162

Page 163: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

}

// przeksztalcenie dokumentu wejsciowego w dokument wyjsciowy transform_doc( books : input_doc ) : output_doc { output : output_doc;

foreach (input_doc.books.book as b) output.html.body.(create transform_doc(b) as book);

return output_doc; }}

W podobny sposób wyobrazić można sobie zastosowanie aktualizowalnych perspektyw SBQL do

transformacji danych danych XML. Zamiast materializacji danych, podejście oparte na

perspektywach umożliwia dynamiczne generowanie nowych dokumentów, jak i ich

modyfikowanie w taki sposób, by każda zmiana była automatycznie odzwierciedlona

w dokumencie źródłowym.

Jak widać, SBQL daje praktycznie nieograniczone możliwości w zakresie przetwarzania danych

XML bez konieczności wprowadzania specjalnej składni charakterystycznej dla narzędzi

przetwarzających XML. Naturalnie specjalna składnia w każdej chwili może zostać wprowadzona

(być może nawet w ramach tego samego narzędzia), jednak użyte w niej konstrukcje powinny być

odpowiednio tłumaczone na wewnętrzne operacje podejścia stosowego.

Przykładowo, do składni SBQL można by wprowadzić konstrukcję nazwa(zapytanie) równoważną

z zapytaniem zapytanie as nazwa. Przy tym założeniu, operację utworzenia nowego egzemplarza

zmiennej doc (zdefiniowanej wcześniej) można byłoby wyrazić w nieco czytelniejszej formie:

create doc( a( #text1(“b”), c(@d(“xxx”), #text(“e”)), #text2(“f”), g(#text(“aaa”)) ));

Inna możliwość, to bezpośrednie wprowadzenie do składni SBQL składni XML. Pomimo innej

składni, zaprezentowana niżej operacja powinna być semantycznie równoważna z operacją podaną

powyżej:

create <a> b <c d = “xxx”>e</c>

163

Page 164: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

f <g>aaa</g> </a> as doc;

Generalnie, przedstawiony wyżej schemat postępowania z danymi XML jest tylko jednym z wielu

możliwych podejść do tego samego tematu. Podstawową trudnością z danymi XML jest takie ich

reprezentowanie za pomocą modelu danych M0 podejścia stosowego, by zachować możliwie

największy stopień funkcjonalności SBQL przy jednoczesnej łatwości obsługi i możliwie

największym zbiorze struktur XML dostępnych dla języka zapytań. “Bezinwazyjne” przetwarzanie

danych XML za pomocą języka SBQL jest jak najbardziej możliwe przy zachowaniu elegancji

rozwiązania niemożliwej do osiągnięcia przez relacyjne bazy danych (np. w XML DB firmy

Oracle).

164

Page 165: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Dodatek E:Ważniejsze operacje maszyny wirtualnej SBQL

Poniżej przedstawiono listę operacji kodu bajtowego. Opis każdej operacji składa się z jej

tekstowego objaśnienia oraz tabelki przedstawiającej parametry zapisane razem z operacją,

pobierane przez nią argumenty ze stosu QRES, jak i rezultat jaki wkładany jest na ten stos.

parametr operacji

argument zdejmowany z QRES

argument nie zdejmowany z QRES

rezultat operacji wkładany na QRES

Stos rezultatów

dup (duplicate)

Kopiuje szczytowy element stosu QRES bez jego zdjemowania.

Result Result

165

Page 166: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

ldi, ldd (load integer, load double)

Ładuje wartość całkowitą lub rzeczywistą na stos rezultatów.

Integer IntegerResult

Double DobuleResult

ldt, ldf (load true, load false)

Umieszcza true lub false na szczycie stosu rezultatów.

BooleanResult

ldn (load null)

Umieszcza referencję z wartością null na szczycie stosu rezultatów.

ReferenceResult

lda (load address)

Umieszcza na szczycie stosu rezultatów referencję do trwałego obiektu przechowywanego w bazie danych pod adresem

podanym jako argument. Operacja ta zawzwyczaj umieszczana jest przez moduł ładujący kod do interpretera zamiast

operacji ldfn i ldmn gdy znana jest dokładna lokalizacja obiektów wskazywanych przez te operacje za pomocą nazw.

Integer ReferenceResult

ldsc (load string constant)

Umieszcza na szczycie stosu QRES wartość pobraną z puli stałych, przechowywaną tam pod indeksem podanym jako

parametr.

Integer StringResult

Stos środowiskowy

crenv (create environment)

Tworzy nową sekcję na stosie środowiskowym. Statyczny link będzie wskazywał na poprzednią (po utworzeniu nowej)

sekcję.

crgenv (create global environment)

Tworzy nową sekcję na stosie środowiskowym. Statyczny link będzie równy null, czyli bindery znajdujące się

w sekcjach poniżej tworzonej sekcji nie będą mogły być związane.

dsenv (destroy environment)

Usuwa szczytową sekcję ze stosu środowiskowego.

166

Page 167: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

nstd (nested)

Realizuje operację nested, a jej wynik (jeśli istnieje) umieszcza w szczytowej sekcji stosu środowiskowego.

Result

bnd (bind)

Realizuje operację bind, umieszczając jej wynik na stosie rezultatów. Parametrem jest nazwa przechowywana

w indeksie nazw.

Integer Result

crbnd (create binder)

Tworzy nowy binder w szczytowej sekcji stosu ENVS. Binder posiada nazwę taką, jak parametr operacji, a wartością

bindera jest wartość pobrana ze stosu QRES.

Integer Result BinderResult

elvb (enter local variable binder)

Wkłada na stos środowiskowy binder do zmiennej lokalnej identyfikowanej w lokalnym składzie danych pod numerem

będącym parametrem. Adres korzenia lokalnego składu danych w którym przechowywane są obiekty bieżącego

środowiska pobierany jest ze szczytowej sekcji stosu środowiskowego.

Integer

rmb (remove binder)

Wiąże nazwę na stosie środowiskowym, a następnie usuwa z niego wszystkie znalezione bindery. Parametrem jest

nazwa przechowywana w indeksie nazw.

Integer

ldcntr (load counter)

Ładuje na QRES zawartość licznika przechowywanego w szczytowej sekcji ENVS.

IntegerResult

stcntr (store counter)

Ustawia licznik przechowywany w bieżącej sekcji stosu środowiskowego na wartość pobraną ze szczytu stosu QRES.

IntegerResult

inccntr (increment counter)

Zwiększa o 1 wartość licznika pochodzącego z bieżącej sekcji stosu środowiskowego.

Page 168: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

deccntr (decrement counter)

Zmniejsza o 1 wartość licznika pochodzącego z bieżącej sekcji stosu środowiskowego.

Skład danycheimpo (enter imported objects)

Umieszcza w szczytowej sekcji stosu środowiskowego referencje do obiektów $data modułów importowanych przez

moduł którego referencję pobiera ze stosu rezultatów. Referencje te pobierane są z podobiektów $linkedimports

bieżącego modułu. Referencję modułu można umieścić na QRES za pomocą ldmn.

ReferenceResult

crlse (create local store entry)

Tworzy nowy obiekt złożony $locobj w stercie i zapisuje jego referencję w specjalnym polu szczytowej sekcji stosu

ENVS. Do obiektu tego podłączane będą obiekty lokalne (np. zmienne deklarowane w procedurach). Operacja zwraca

referencję utworzonego w ten sposób obiektu.

ReferenceResult

ldlse (load local store entry)

Ładuje na QRES referencję do obiektu $locobj przechowywanego w stercie i utworzonego za pomocą crlse. Referencja

ta odczytywana jest ze specjalnego pola w szczytowej sekcji stosu środowiskowego.

ReferenceResult

crsse (create session store entry)

Tworzy w stercie obiekt złożony $sesobj oraz zwraca jego referencję. Oprócz tego, referencja ta wraz z referencją do

bieżącego modułu (będącą argumentem operacji) są zapamiętywane w specjalnej zmiennej sesobj, przechowywanej

przez proces SVRP w obiekcie reprezentującym sesję. Umożliwia to później umieszczenie na stosie ENVS binderów do

obiektów sesyjnych zdefiniowanych w module o określonym adresie. Operacja umieszczana jest zwykle w procedurze

systemowej $initso.

ReferenceResult ReferenceResult

ldsse (load session store entry)

Umieszcza w szczytowej sekcji stosu środowiskowego referencję do korzenia obiektów sesyjnych modułu, którego

adres podany został jako argument. Przy pierwszym odwolaniu do tego modułu w ramach bieżącej sesji, obiekty

sesyjne są automatycznie tworzone (przez wywołanie procedury $initso, zawierającej kod odpowiedzialny za

utworzenie zmiennych sesyjnych).

168

Page 169: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

ReferenceResult ReferenceResult

ldfn (load field by name)

Ładuje na QRES referencję do obiektu globalnego jakiegoś modułu. Obiekt wyszukiwany jest wg nazwy składającej się

z globalnej nazwy modułu oraz nazwy obiektu rozdzielonych znakiem #. Podczas ładowania kodu do interpretera (czyli

wówczas, gdy adres obiektu jest już znany), nazwa ta zamieniana jest na właściwą referencję, a operacja ldfn

zastępowana jest przez lda.

String ReferenceResult

ldmn (load module by name)

Ładuje na QRES referencję do modułu o globalnej nazwie podanej jako parametr. Podczas ładowania kodu do

interpretera, nazwa zamieniana jest na właściwą referencję, a operacja ldmn zastępowana jest przez lda.

String ReferenceResult

ldmen (load module entry by name)

Działa podobnie jak ldmn, ale na QRES ładowana jest referencja do obiektu $data modułu którego nazwa jest

argumentem.

String ReferenceResult

Operacje na obiektach

dynder (dynamic dereference)

Realizuje operację dereferencji nie znając rodzaju obiektu, na którym będzie realizowana (sprawdza to w czasie

wykonania). Jeśli argument nie jest obiektem ReferenceObject, wówczas nic się nie dzieje.

Result Result

deri, derd, ders, derb, derr, derc (dereference integer, double, string, boolean, reference, complex).

Realizuje operację dereferencji znając rodzaj obiektu na którym operacja będzie realizowana. Przykładowo, operacja

deri zakłada że referencja prowadzi do obiektu INTEGER_OBJECT, zatem może łatwo odczytać wartość tego obiektu

i umieścić na stosie QRES obiekt IntegerObject z tą wartością. Operacja derc (dereferencja obiektu złożonego)

umieszcza na stosie QRES obiekt StructResult składający się z binderów o nazwach będących nazwami podobiektów

danego obiektu złożonego oraz wartościach będących wartościami tych obiektów. Jeśli na tym samym poziomie

hierarchii znajduje się większa niż 1 obiekt o tej samej nazwie, wówczas wartością bindera jest bag z wartościami

będącymi wartościami tych obiektów.

ReferenceResult Result

Page 170: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

sti, sts, std, stb, str (store integer, string, boolean, reference)

Zapisuje wartość integer, string, boolean lub referencję w obiekcie którego referencję podano jako pierwszy argument.

ReferenceResult IntegerResult

ReferenceResult StringResult

ReferenceResult DoubleResult

ReferenceResult BooleanResult

ReferenceResult ReferenceResult

ststr (store struct)

Przypisuje wartości podane w strukturze będącej drugim argumentem podobiektom obiektu którego referencję podano

jako pierwszą wartość. Struktura musi mieć odpowiedni format, tzn. składać się z binderów posiadających takie nazwy,

jak nazwy podobiektów (patrz kopiowanie strukturalne opisane w rozdziale o SBQL).

ReferenceResult StructResult

cri, crs, crd, crb, crc, crr, cra (create integer, string, double, boolean, complex, reference, aggregate)

Tworzy obiekty INTEGER_OBJECT, STRING_OBJECT, DOUBLE_OBJECT, BOOLEAN_OBJECT,

COMPLEX_OBJECT, REFERENCE_OBJECT, AGGREGATE_OBJECT. Obiekt posiadał będzie nazwę o

identyfikatorze (w indeksie nazw) podanym jako parametr. Argumentem jest referencja do obiektu nadrzędnego, a

rezultatem referencja do utworzonego obiektu.

Integer ReferenceResult ReferenceResult

ren (rename)

Zmienia nazwę obiektów których referencje podane zostaną jako elementy kolekcji będącej argumentem operacji.

Nazwę zmienia tylko obiekt będący w bazie danych, metabaza pozostaje bez zmian.

Integer CollectionResult<ReferenceResult>

mov (move)

Przenosi obiekty o identyfikatorach będących elementami kolekcji podanej jako pierwszy argument, podłączając je do

obiektu będącego drugim parametrem. Przenoszony jest tylko obiekt będący w bazie danych, metabaza pozostaje bez

zmian. Podczas przenoszenia aktualizowane są również wszystkie referencje wskazujące na przenoszone obiekty w taki

sposób, że po przeniesieniu wskazywać będą na nową lokalizację. Do wyszukania obiektów referencyjnych

170

Page 171: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

wykorzystywane są referencje zwrotne przechowywane razem z przenoszonymi obiektami.

CollectionResult<ReferenceResult> ReferenceResult

del (delete)

Usuwa obiekt o identyfikatorze podanym jako argument. Usuwany jest tylko obiekt będący w bazie danych, metabaza

pozostaje bez zmian.

CollectionResult<ReferenceResult>

Operacje sterujące

nop (no operation)

Brak operacji.

bra (branch always)

Realizuje operację skoku bezwarunkowego do pozycji w kodzie bieżącej procedury (licząc od 0) podanej jako parametr

operacji.

Integer

brt, brf (branch if true, branch if false)

Realizuje operację skoku warunkowego do pozycji w kodzie bieżącej procedury (licząc od 0) podanej jako parametr

operacji. Skok realizowany jest tylko wówczas, gdy drugi argument jest równy true.

Integer BooleanResult

call (call)

Wywołuje procedurę wskazywaną przez referencję pobraną ze stosu rezultatów.

ReferenceResult

ret (return)

Umieszcza na QRES pustego baga i kończy wykonywanie procedury.

BagResult

retv (return value)

Kończy wykonywanie procedury. Zakłada że na stosie rezultatów znajduje się rezultat zwracany przez procedurę.

Result

Page 172: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Konwersjei2s, i2d (integer to string, integer to double)

Konwertuje liczbę typu integer pobraną ze szczytu QRES do wartości string lub double.

IntegerResult StringResult

IntegerResult DoubleResult

d2i, d2s (double to integer, double to string)

Konwertuje liczbę double pobraną ze szczytu QRES do wartości integer lub string.

DoubleResult IntegerResult

DoubleResult StringResult

s2i, s2d (string to integer, string to double)

Konwertuje wartość string pobraną ze szczytu QRES do wartości integer lub double.

StringResult IntegerResult

StringResult DoubleResult

b2s (boolean to string)

Konwertuje wartość boolean pobraną ze szczytu QRES do wartości string.

BooleanResult StringResult

dyn2s, dyn2i, dyn2d (dynamic to string, integer, double)

Konwertuje wartość pobraną ze szczytu stosu do wartości string, integer lub double.

SingleResult StringResult

SingleResult IntegerResult

SingleResult DoubleResult

fltn (flatten)

Sprawdza czy argument jest kolekcją jednoelementową. Jeśli tak, wówczas przestaje on być kolekcją. W przeciwnym

razie pozostaje bez zmian.

172

Page 173: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Result SingleResult

bag

Przeciwieństwo operatora fltn. Pobiera rezultat ze stosu QRES i zamienia go na bag. Jeśli na stosie był jeden element,

wówczas bag wynikowy zawiera jeden element. Jeśli na stosie był bag, wówczas nic się nie dzieje.

Result CollectionResult

Nazwy pomocnicze

as

Tworzy bindery na podstawie szczytowej wartości na stosie QRES. Jeśli argumentem jest kolekcja, wówczas jest to

kolekcja binderów. Jeśli argumentem jest pojedyncza wartość, wówczas jest to pojedynczy binder. Bindery posiadają

nazę taką, jaka została podana jako parametr operacji (wartość jest numerem pozycji w indeksie nazw).

Integer Result Result

gas (group as)

Tworzy pojedynczy binder na podstawie szczytowej wartości na stosie QRES. Binder posiada nazę taką, jaka została

podana jako parametr operacji.

Integer Result BinderResult

Operacje na kolekcjach

cnt (count)

Zlicza elementy kolekcji.

CollectionResult<SingleResult> IntegerResult

exts (exists)

Sprawdza czy kolekcja jest pusta, czy nie.

CollectionResult<SingleResult> IntegerResult

extr (extract)

Wybiera element o podanym indeksie z kolekcji wartości.

CollectionResult<SingleResult> IntegerResult SingleResult

ins2 (insert to second)

Wkłada wartość pobraną QRES do kolekcji będącej drugim elementem (po zdjęciu argumentu) na szczycie tego stosu.

Page 174: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

CollectionResult<SingleResult> Result SingleResult

sum (sum)

Dodaje do siebie elementy jakiejś kolekcji zawierającej wartości integer lub double. Przed zrealizowaniem operacji

elementy kolekcji muszą zostać poddane dereferencji.

CollectionResult<SingleResult> IntegerResult

in

Sprawdza czy wszystkie elementy jednej kolekcji należą do drugiej kolekcji. Porównywanie takich rezultatów zachodzi

strukturalnie. Przed zrealizowaniem porównania referencje obu kolekcji muszą zostać poddawane dereferencji.

CollectionResult<SingleResult> CollectionResult<SingleResult> IntegerResult

unn (union)

Sumuje dwie kolekcji na zasadzie sumy zbiorów..

CollectionResult<SingleResult> CollectionResult<SingleResult> CollectionResult<SingleResult>

intsct (intersect)

Wylicza część wspólną dwóch kolekcji. Przed zrealizowaniem porównania referencje obu kolekcji muszą zostać

poddawane dereferencji.

CollectionResult<SingleResult> CollectionResult<SingleResult> CollectionResult<SingleResult>

crpd (carthesian product)

Wylicza iloczyn kartezjański dwóch kolekcji.

CollectionResult<SingleResult> CollectionResult<SingleResult> CollectionResult<StructResult>

diff (difference)

Wylicza różnicę dwóch zbiorów. Przed zrealizowaniem porównania referencje obu kolekcji muszą zostać poddawane

dereferencji.

CollectionResult<SingleResult> CollectionResult<SingleResult> CollectionResult<SingleResult>

ordr (order)

Sortuje kolekcję rezultatów. Kolekcja musi składać się ze struktur <SingleResult, SingleResult1, SingleResult2, ...,

SingleResultn>. Obiekty SingleResultx to klucze, wg których będzie realizowane sortowanie. Klucze muszą zostać

poddane uprzedniej dereferencji. Wynikiem jest kolekcja składająca się wyłącznie z pierwszych pól tych struktur.

CollectionResult<StructResult> CollectionResult<SingleResult>

174

Page 175: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

unq (unique)

Usuwa powtórzenia z kolekcji, nie znając rodzajów rezultatów w niej przechowywanych. Przed wykonaniem operacji

argument powinien zostać poddany dereferencji.

CollectionResult<SingleResult> CollectionResult<SingleResult>

max (maximum)

Wylicza maksymalną wartość znajdującą się w kolekcji. Kolekcja może zawierać tylko rezultaty będące liczbami

integer, albo double. Jeśli znajduje się w niej choć jeden inny rezultat, wówczas zgłaszany jest błąd czasu wykonania.

Przed wykonaniem operacji argument powinien zostać poddany dereferencji

CollectionResult<SingleResult> CollectionResult<SingleResult>

min (minimum)

Wylicza minimalną wartość znajdującą się w kolekcji. Kolekcja może zawierać tylko rezultaty będące liczbami integer,

albo double. Jeśli znajduje się w niej choć jeden inny rezultat, wówczas zgłaszany jest błąd czasu wykonania. Przed

wykonaniem operacji argument powinien zostać poddany dereferencji

CollectionResult<SingleResult> CollectionResult<SingleResult>

avg (average)

Wylicza średnią rezultatów będących elementami kolekcji. Kolekcja może zawierać tylko rezultaty będące liczbami

typu integer, albo double. Jeśli znajduje się w niej choć jeden inny rezultat, wówczas zgłaszany jest błąd czasu

wykonania. Przed wykonaniem operacji argument powinien zostać poddany dereferencji.

CollectionResult<SingleResult> CollectionResult<SingleResult>

Operacje arytmetyczne i konkatenacja

addi, addd, adds (add integer, double, string)

Dodaje dwie liczby integer, albo dwie liczby double. Operacja adds konkatenuje ciągi znaków.

IntegerResult IntegerResult IntegerResult

DoubleResult DoubleResult DoubleResult

StringResult StringResult StringResult

muli, muld (multiplicate integer, double)

Mnoży dwie liczby integer, albo dwie liczby double.

Page 176: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

IntegerResult IntegerResult IntegerResult

DoubleResult DoubleResult DoubleResult

subi, subd (static subtract integer, static subtract double)

Odejmuje od siebie dwie liczby integer, albo dwie liczby double.

IntegerResult IntegerResult IntegerResult

DoubleResult DoubleResult DoubleResult

divi, divd (divide integer, divide double)

Dzieli przez siebie dwie liczby typu integer, albo dwie liczby double.

IntegerResult IntegerResult IntegerResult

DoubleResult DoubleResult DoubleResult

modi, modd (module integer, module double)

Wylicza resztę z dzielenia dwóch liczb typu integer lub dwóch liczb double.

IntegerResult IntegerResult IntegerResult

DoubleResult DoubleResult DoubleResult

negi, negr (negation integer, negation double)

Zamienia znak liczby integer lub liczby double na przeciwny.

IntegerResult IntegerResult

DoubleResult DoubleResult

dynadd, dynmul, dyndiv, dynmod, dynneg (dynamic add, multiplicate, divide, modulo, negation)

Dynamicznie dodaje, mnoży, dzieli, wylicza resztę z dzielenia lub zamienia znak na przeciwny.

SingleResult SingleResult

176

Page 177: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Operacje logiczneand, or

Wylicza iloczyn lub sumę logiczną.

BooleanResult BooleanResult BooleanResult

gri, grd (greater integer, greater double)

Sprawdza czy jedna liczba integer lub double jest większa od drugiej.

IntegerResult IntegerResult BooleanResult

DoubleResult DoubleResult BooleanResult

grei, gred (greater or equals integer, greater or equals double)

Sprawdza czy jedna liczba integer lub double jest większa lub równa od drugiej.

IntegerResult IntegerResult BooleanResult

DoubleResult DoubleResult BooleanResult

loi, lod (lower integer, lower double)

Sprawcza czy jedna liczba typu integer lub double jest mniejsza od drugiej.

IntegerResult IntegerResult BooleanResult

DoubleResult DoubleResult BooleanResult

loei, loed (lower or equals integer, lower or equals double)

Sprawdza czy jedna liczba integer lub double jest mniejsza lub równa drugiej.

IntegerResult IntegerResult BooleanResult

DoubleResult DoubleResult BooleanResult

eqi, eqd, eqb, eqs, eqr (equals integer, equals double, equals boolean, equals string, equals reference)

Sprawdza czy dwie liczby integer, boolean, double, string lub referencje są sobie równe.

IntegerResult IntegerResult BooleanResult

Page 178: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

DoubleResult DoubleResult BooleanResult

StringResult StringResult BooleanResult

DoubleResult DoubleResult BooleanResult

ReferenceResult ReferenceResult BooleanResult

eqstr (equals struct)

Porównuje strukturalnie dwie struktury.

StructResult StructResult BooleanResult

dyngr, dyngre, dynlo, dynloe, dyneq (dynamic greater, lower, lower or equals, equals)

Dynamiczne wersje operaacji większości, mniejszości, mniejszości lub równości, równości.

SingleResult SingleResult BooleanResult

not

Neguje wartość boolean.

BooleanResult BooleanResult

178

Page 179: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Lista ważniejszych akronimów użytych w pracy

ADO - ActiveX Data Objects

API - Application Programming Interface

AST - Abstract Syntax Tree

B2B - Business-To-Business

CLI - Call-Level Interface

CLI - Command-Line Interface

CORBA - Common Object Request Architecture

DBMS - Database Management System

DCOM - Distributed Component Object Model

EAI - Enterprise Application Integration

EII - Enterprise Information Integration

EJB - Enterprise Java Beans

EJB QL - Enterprise Java Beans Query Language

ENVS - Environment Stack

179

Page 180: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

ESB - Enterprise Service Bus

HQL - Hibernate Query Language

JDBC - Java Database Connectivity

JMS - Java Messaging Service

LSNR - Listener

ODL - Object Definition Language

ODMG - Object Database Management Group

ODRA - Object Database for Rapid Application development

OID - Object IDentifier

OMG - Object Management Group

OQL - Object Query Language

P2P - Peer To Peer

PJWSTK - Polsko-Japońska Wyższa Szkoła Technik Komputerowych

QRES - Query Result Stack

RAD - Rapid Application Development

SBA - Stack-Based Approach

SBQL - Stack-Based Query Language

SOA - Service Oriented Architecture

SQL - Structured Query Language

SVRP - SerVeR Process

SZBD - System Zarządzania Bazą Danych

SZFBD - System Zarządzania Federacyjną Bazą Danych

SZRBD - System Zarządzania Relacyjną Bazą Danych

SZOBD - System Zarządzania Obiektową Bazą Danych

UML - Unified Modelling Language

VIDE - Visualize all moDel drivEn programming

180

Page 181: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

XML - eXtensible Markup Language

XSLT - eXtensible Stylesheet Language Transformations

Page 182: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp
Page 183: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

Literatura

1. P. Lyman, H. Varian, A. Dunn, A. Strygin, and K. Swearingen, How Much Information?,

http://www.sims.berkeley.edu/research/projects/how-much-info/.

2. A.Y. Halevy, N. Ashish, D. Bitton, M.J. Carey, D. Draper, J. Pollock, A. Rosenthal, V. Sikka

(2005). Enterprise information integration: successes, challenges and controversies. SIGMOD

2005, 778-787.

3. M. Roth and D. Wolfson, From Data Management to Information Integration: A Natural

Evolution http://www7b.software.ibm.com/dmdd/library/techarticle/0206roth/0206roth.html

4. K. Subieta, Teoria i konstrukcja obiektowych języków zapytań, Wydawnictwo PJWSTK,

Warszawa 2004.

5. H. Garcia-Molina, J.D. Ullman, J. Widom, Implementacja systemów baz danych, WNT,

Warszawa 2003.

6. K. Subieta, Obiektowość w projektowaniu i bazach danych, Akademicka Oficyna Wydawnicza

PLJ, Warszawa 1998.

7. J. Płodzień, Optimization Methods in Object-Oriented Database Management Systems,

rozprawa doktorska, IPI PAN, Warszawa 2000.

8. K. Kaczmarski, Metodologie i metamodele dla obiektowych baz danych typu grid, rozprawa

doktorska, IPI PAN, Warszawa 2006.

9. K. Stencel, Półmocna kontrola typów w językach programowania baz danych, Wydawnictwo

PJWSTK, Warszawa 2006.

183

Page 184: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

10. J.M. Myerson, The Complete Book of Middleware, Auerbach Publications, 2002.

11. D.S. Lithicum, Next Generation Application Integration: From Simple Information to Web

Services, Addison Wesley, 2003.

12. M. Atkinson, R. Morrison. Orthogonally Persistent Object Systems. The VLDB Journal 4(3),

319-401, 1995. R.G.G.Cattell, D.K.Barry (Eds.): The Object Data Standard: ODMG 3.0.

Morgan Kaufmann 2000.

13. W.R. Cook, C. Rosenberger: Native Queries for Persistent Objects A Design White Paper.

http://www.db4o.com/about/productinformation/whitepapers/Native%20Queries

%20Whitepaper.pdf, 2006

14. H. Kozankiewicz, K. Stencel, K. Subieta: Integration of Heterogeneous Resources through

Updatable Views. Workshop on Emerging Technologies for Next Generation GRID

(ETNGRID-2004), June 2004, Proc. published by IEEE.

15. H. Kozankiewicz, J. Leszczylowski, K. Subieta: Updateable XML Views. Proc. of ADBIS’03,

Springer LNCS 2798, 2003, 385-399.

16. J. Plodzien, A. Kraken: Object Query Optimization in the Stack-Based Approach. Proc. ADBIS

Conf., Springer LNCS 1691, 3003-316, 1999.

17. K. Subieta: Stack-Based Approach (SBA) and Stack-Based Query Language (SBQL). http://

www.sbql.pl, 2006.

18. World Wide Web Consortium (W3C) : Extensible Markup Language (XML), http://

www.w3.org/XML/.

19. World Wide Web Consortium (W3): XML Query specifications. http://www.w3.org/XML/

Query/

20. Hibernate - Relational Persistence for Java and .NET. http://www.hibernate.org/, 2006

21. db4o - Native Java & .NET Object Database. http://www.db4o.com.

22. Objectivity - Object Oriented Database. http://www.objectivity.com.

23. M. Atkinson, M. Jordan, L. Daynes and S. Spence. Design Issues for Persistent Java: a type-

safe, object-oriented, orthogonally persistent system, 7th International Workshop on Persistent

Object Systems, Cape May, 1996.

184

Page 185: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

24. A.L. Hosking and J. Chen. Persistent Modula 3: An Orthogonally Persistent Systems

Programming Language - Design, Implementation, Performance. In Proceedings of the 25th

International Conference on Very Large Data Bases (Edinburgh, Scotland, September 1999).

Morgan Kaufmann, 1999.

25. Common Object Request Broker Architecture: Core Specification, OMG, 2004,

http://www.omg.org/docs/formal/04-03-12.pdf.

26. S. Alagic. The ODMG Object Model: Does it Make Sense? Proc. OOPSLA Conf., 253-270,

1997.

27. Object Data Management Group: The Object Database Standard ODMG, Release 3.0.

R.G.G.Cattel, D.K.Barry, Ed., Morgan Kaufmann, 2000.

28. A. Albano, G. Ghelli, R. Orsini. Fibonacci: A Programming Language for Object Databases.

The VLDB Journal 4(3), 403-444, 1995.

29. H. Baker. Iterators. Signs of Weakness in Object-Oriented Languages. ACM OOPS Messenger

4(3), 18-25, http://home.pipeline.com/~hbaker1/, 1993.

30. K. Subieta, M. Missala, and K. Anacki. The LOQIS System. Description and Programmer

Manual. Institute of Computer Science of PAS Report 695, 1990.

31. K. Subieta. A Persistent Object Store for the LOQIS Programming System. International Journal

on Microcomputer Applications 13(1), 50-61, 1994.

32. F. Bancilhon. Understanding Object-Oriented Database Systems. Proc. EDBT Conf., Springer

LNCS 580, 1-9, 1992.

33. S.S. Chawathe, H. Garcia-Molina, A. Gupta, J. Hammer, K. Ireland, Y. Papakonstantinou,

D. Quass, A. Rajaraman, Y. Sagiv, J. Ullman, J. Widom. The TSIMMIS Project, 1994-95; http://

www-db.stanford.edu/pub.

34. D. Figura. Obiektowe bazy danych. Akademicka Oficyna Wydawnicza, Warszawa 1996.

35. W. Kim. Wprowadzenie do obiektowych baz danych. Wydawnictwa Naukow-Techniczne,

Warszawa 1996.

36. M.E.S. Loomis. Object Databases: The Essentials. Addison Wesley, 1995.

Page 186: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

37. A. Heuer, M.H. Scholl. Principles of Object-Oriented Query Languages. Proc. GI Conf. on

Database Systems for Office, Engineering and Scientific Applications, Springer-Verlag,

178-197, 1991.

38. H. Kozankiewicz, J. Leszczyłowski, K. Subieta. Implementing Mediators through Virtual

Updateable Views. Proc. EFIS’03, IOS Press, 52-62, 2003.

39. M. Jarke, J. Koch. Query Optimization in Database Systems. ACM Computing Surveys 16(2),

111-152, 1984.

40. A. Kemper, G. Moerkotte. Query Optimization in Object Bases: Exploiting Relational

Techniques. (In) Query Processing for Advanced Database Systems. Morgan Kaufmann, 63-98,

1994.

41. F. Matthes, A. Rudloff, J.W. Schmidt, K. Subieta. The Database Programming Language

DBPL, User and System Manual. FIDE, ESPRIT BRA Project 3070, Technical Report Series,

FIDE/92/47, 1992 (również: Fachbereich Informatik Universitaet Hamburg, Bericht Nr. 159,

FBI-HH-B-159/92, 1992).

42. G.Wiederhold. Mediators in the Architecture of Future Information Systems, IEEE Computer

Magazine, 1992.

43. Pascal/R Report, J.W. Schmidt et al, U Hamburg, Fachbereich Informatik, Report 66, Jan 1980.

44. R. Morrison, F. Brown, R. Connor, Q. Cutts, A. Dearle, G. Kirby, D. Munro The Napier88

Reference Manual Release 2.0, 1994.

45. F. Matthes, Persistente Objektsysteme: Integrierte Datenbankentwicklung und

Programmerstellung. Springer-Verlag, 1993.

46. A. Ohori, P. Buneman, V. Breazu-Tannen. Database Programming in Machiavelli a

Polymorphic Language with Static Type Inference (1992).

47. McLeod and Heimbigner. A Federated architecture for information management. ACM

Transactions on Information Systems Vol 3, Issue 3 (1985): 253-278.

48. Sheth and Larson. Federated Database Systems for Managing Distributed, Heterogenous, and

Autonomous Databases. ACM Computing Surveys Vol 22, No.3 (1990): 183-236.

49. A. Tomasic, R. Amouroux, P. Bonnet, The Distributed Information Search Component (DisCo)

and the World Wide Web.

186

Page 187: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

50. R. Ahmed, et al. The Pegasus Heterogeneous Multidatabase System. In IEEE Computer, Vol.

24, 1991.

51. L. Haas, E. Lin. IBM Federated Database Technology, IBM 2002.

52. EJB 2.1 Specification, Sun Microsystems, http://java.sun.com/products/ejb/docs.html.

53. H. Kozankiewicz, Updateable Object Views, praca doktorska, IPI PAN 2005.

54. Comega language, http://research.microsoft.com/Comega.

55. LINQ Project, http://msdn2.microsoft.com/en-us/netframework/aa904594.aspx.

56. Garlic Project, http://www.almaden.ibm.com/cs/garlic.

57. U. Strathclyde, The PS-Algol Reference Manual, TR PPR-12-85, CS Dept, University of

Glasgow.

58. S. Ceri and S. Navathe. A methodology for the distribution design of databases. In IEEE

COMPCON 26, San Francisco, 1983.

59. S. Ceri, M. Negri, and G. Pelagatti. Horizontal data partitioning in database design. In

SIGMOD Conference, pages 128–136, 1982.

60. S. Ceri and G. Pelagatti. Distributed databases: Principles and systems. McGraw-Hill, Inc. New

York, NY, USA, 1984.

61. S. Ceri, B. Pernici, and G. Wiederhold. Distributed database design methodologies. In

Proceedings of the IEEE, volume 75, pages 533–546, 1987.

62. DataGrid. The DataGrid Project Website. eu-datagrid.web.cern.ch/eu-datagrid/.

63. C. J. Date. An Introduction to Database Systems. Adison-Wesley, 1995.

64. eGov Bus Consortium. Advanced Egovernment Information Service Bus. website: www.egov-

bus.org, 2006.

65. M. Stonebraker, L. A. Rowe, B. G. Lindsay, J. Gray, M. J. Carey, and D. Beech. The Committee

for Advanced DBMS Function: Third Generation Data Base System Manifesto. In H. Garcia-

Molina and H. V. Jagadish, editors, Proceedings of the 1990 ACM SIGMOD International

Conference on Management of Data, Atlantic City, NJ, May 23-25, 1990, page 396. ACM Press,

1990.

Page 188: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

66. N. Wirth. The module: A system structuring facility in high-level programming languages. In

Language Design and Programming Methodology, pages 1–24, 1979.

67. N. Wirth. Programming in Modula 2. Springer, 1982.

68. Oracle Corporation. Oracle database concepts 10g, 2005.

69. Oracle Corporation. PL/SQL Programmer’s manual, 2005.

70. D. L. Parnas. On the criteria to be used in decomposing systems into modules. Commun. ACM,

15(12):1053–1058, 1972.

71. Rational Software Corporation. The UML and data modeling, 2000.

72. J. Rumbaugh, M. Blaha, W. Premerlani, F. Eddy, and W. Lorensen. Object-Oriented Modeling

and Design. Prentice-Hall, 1991.

73. J. Rumbaugh, I. Jacobson, and G. Booch. The Unified Modeling Language Reference Manual.

Addison-Wesley, 1998.

74. I. Sommerville. Software Engineering. Addison-Wesley, 2001.

75. B. G. Lindsay, L. M. Haas, C. Mohan, P. F. Wilms, and R. A. Yost. Computation and

communication in R*: a distributed database manager. ACM Trans. Comput. Syst., 2(1):24–38,

1984.

76. B. Meyer. Object-Oriented Software Construction. Prentice-Hall, 2000.

77. E. Naiburg and R. A. Maksimchuk. UML for Database Design. Addison-Wesley, 2001.

78. S. B. Navathe, S. Ceri, G. Wiederhold, and J. Dou. Vertical partitioning algorithms for

database design. ACM Trans. Database Syst., 9(4):680–710, 1984.

79. Object Management Group. Unified Modeling Language (UML), version 2.0. website:

www.omg.org/technology/documents/formal/uml.htm, 2003.

80. K. Kaczmarski, P. Habela, and K. Subieta. Metadata in a data grid construction. In WETICE,

pages 315–316. IEEE Computer Society, 2004.

81. K. D. Levin and H. L. Morgan. Optimizing distributed data bases: A framework for research. In

Proc. National Computer Conf., pages 473–478, 1975.

188

Page 189: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

82. M. Lenzerini. Data integration: a theoretical perspective. In Proceedings of the twenty-first

ACM SIGMOD-SIGACT-SIGART symposium on Principles of database systems, Madison,

Wisconsin, 2002.

83. D. Laurent, J. Lechtenborger, N. Spyratos, and G. Vossen. Complements for data warehouses. In

Proc. of 15th Conference on Data Engineering, pages 490–499, 1999.

84. J. Górski. Inżynieria Oprogramowania w projekcie informatycznym. Mikom, 2000.

85. A. Jaszkiewicz. Inżynieria Oprogramowania. Helion, 1997.

86. IBM Research Laboratory. R*: An overview of the architecture. Technical Report RJ3325, IBM

Research Laboratory, 1982.

87. ISO/IEC 9075:1992. Database language SQL standard. Technical report, ISO, 1992.

88. K. Kaczmarski. Transparent migration of database services. In J. Wiedermann, G. Tel, J.

Pokorny, M. Bielikova, and J. Stuller, editors, SOFSEM, volume 3831 of Lecture Notes in

Computer Science, pages 332–340. Springer, 2006.

89. K. Kaczmarski, P. Habela, H. Kozankiewicz, K. Stencel, and K. Subieta. Transparency in

object-oriented grid database systems. In Paral lel Processing and Applied Mathematics, 6th

International Conference, PPAM 2005, volume 3911 of Lecture Notes in Computer Science,

pages 675–682, 2006.

90. W. Kent. Data and Reality. North-Holland Publishing Company, 1978.

91. K. Subieta: Object-Oriented Standards. Can ODMG OQL Be Extended to a Programming

Language? Cooperative Databases and Applications, World Scientific, pp. 459–468, 1997.

92. K. Subieta, Virtual Persistent Object Store Package (Sun Version), 1991.

93. K. Subieta, J. Leszczyłowski, I. Ulidowski: Processing SemiStructured Data in Object Bases,

ICS PAS Report 852, February 1998.

94. K. Subieta, Y. Kambayashi, J. Leszczyłowski: Procedures in Object-Oriented Query Languages.

Proc. 21-st VLDB Conf., Zurich, pp.182–193, 1995.

95. H. Kozankiewicz, J. Leszczyłowski, K. Subieta: Updateable Views for an XML Query

Language. Proc. of 15th CAiSE, Klagenfurt/Velden, Austria, 2003.

96. H. Kozankiewicz, K. Subieta: SBQL Views – Prototype of Updateable Views. Proc. 8th ADBIS

Conf., Hungary, 2004.

Page 190: Integracja danych i aplikacji przy użyciu wirtualnych ...subieta/SBA_SBQL/phds/PhD Michal Lentner.pdf · W idealnej sytuacji (postulowanej przez tzw. ortogonalną trwałość) dostęp

97. CUP Parser Generator for Java, http://www.cs.princeton.edu/~appel.

98. Fast scanner generator for Java, http://jflex.de.

99. A. Jodłowski: Dynamic Object Roles in Conceptual Modelling and Databases, Ph.D. Thesis,

The Institute of Computer Science, The Polish Academy of Sciences, 2002.

100. W.R. Stevens: Unix Network Programming Prentice Hall 1990.

101. S.R. Gopalan: A Detailed Comparison of CORBA DCOM and Java/RMI (with specific code

examples), http://www.execp.com/~gopalan/misc/compare.html.

102. D.E. Comer: Sieci Komputerowe TCP/IP, WNT, Warszawa 1997.

103. JSR 51: New I/O APIs for the JavaTM Platform, Sun Microsystems, http://jcp.org/en/jsr/

detail?id=51.

104. Java Messaging Service, Sun Microsystems, http://java.sun.com/products/jms/.

105. Spring Framework, http://www.springframework.org/.

190