OQL Jakub Kýpeť, Ondřej Heřmánek
Obsah Historie Objektový model Dotazovací jazyk Příklady
Historie 1993 - vzniká standard ODMG-93 nadmnožina obecného modelu od OMG převzat definiční jazyk IDL dotazovací část OQL podle SQL-92 C++, SmallTalk, Java (později JDO) 2001 - ODMG 3.0
Objektový model Objekt - základní jednotka OML Objekt je instance třídy - typ Třídy definují stav a chování objektů OID, atributy, vazby s jinými objekty, metody Operace nad objekty dědění, zapouzdření, polymorfismus,...
Dědičnost násobná dědičnost tříd třída dědí od předka jeho vlastnosti (k tomu určené), může si přidat vlastní poděděnou třídu lze považovat za předka abstraktní třídy - nelze instanciovat přímo pokud dojde ke kolizi jmen operací u dvou předků, potomek musí definovat obě
Objekt má OID, stav (vlastnosti) a chování (metody) lze definovat klíč(e), index(y) každému objektu unikátní název v rámci "scope" vlastnosti (určují stav) - atributy a relace operace (určují chování) - metody životnost - v proceduře, programu, databázi
Atributy objektu definovány na typu (třídě) objektu dvojice typ a hodnota atributu age: Integer sex: Enumeration("male", "female") height: Integer nastavení a získání hodnoty set_value(new_value:literal) get_value() -> existing_value:literal
Relace mezi objekty namají ani OID, ani jméno definovány mezi dvěma (mutable) objekty podporované typy vztahů - 1:1, 1:N, M:N 1:N a M:N relace mohou být setřízené typ M:N implikuje M relací 1:N a N relací 1:M relace 1:N implikuje N relací typu 1:1
Příklad relace mezi objekty Student se účastní několika kurzů, jednoho kurzu se účastní několik studentů. (relace typu M:N) interface Student { takes: Set<Course> inverse Course::is_taken_by } interface Course { is_taken_by Set<Student> inverse Student::takes }
Metody objektu formálně nazývány operace, určují chování signatura název - unikátní v rámci objektu parametry - literály i objekty návratový typ - objekt, literál i nil potenciální chyby při výpočtu (Java)
Správa chyb hierarchie typů chyb a jejich podtypů chyby jsou odchytávány "handlery" "handler" chybu zpracuje, nebo pošle dál raise -> catch -> dispose (-> abort) po zpracování chyby program pokračuje ve vykonávání příkazu, který následoval po příkazu, jehož volání vyvolalo tu chybu
Datové typy Objekty (Person, Company,..., nil) Literály Boolean (true, false) Integer (111), Float (314.16e-2) Char ('a'), String ("xyz") Date, Time, DateTime, Interval - jako v SQL-92 Enumerátory Strukturované typy Kolekce (Bag, Set, List, Array) Struktury lze definovat vlastní podtypy
Strukturované typy Struktury předem známá velikost - počet a typ objektů může obsahovat objekty různých typů pojmenované pozice objektů address.zip_code = "14800" Kolekce počet objektů v kolekci není předem znám prvky stejného typu (nebo alespoň stejného předka) umístění objektu v kolekci je určeno při vkládání na začátek, na konec, relativně, absolutně,... Bag, Set, List, Array
Kolekce generické kolekce, typ určen deklarací List<Course> - seznam kurzů ve škole přídání, změna či mazání prvku nevytváří novou kolekci lze je indexovat dotaz nad kolekcí vrací jinou kolekci stejného typu Iterování přes kolekce - pomocí iterátorů next(), first(), last(), more?() create_iterator operace na kolekci kolekci lze měnit během iterace u netříděných funguje vždy u tříděných funguje, pokud je prvek změněn před iterátorem (tzn. bude se přes něj ještě iterovat)
Kolekce - změna během iterace class Part { components : Bag<Part>;... } all_components : Bag<Part>; p: Part; all_components := 'some Part'; foreach p in all_components do { all_components := all_components UNION p.components }
Type Set<T> nesetříděná kolekce prvků (pod)typu T,nedovoluje duplicity pokud vkládaný prvek již v kolekci existuje, nic se nestane operace sjednocení dvou kolekcí (union) vrací novou kolekci s unikátními prvky původních kolekcí operace průniku dvou kolekcí (intersect) vrací novou kolekci s prvky, které leží v průniku kolekcí operace rozdílu (differenece) vrací prvky kolekce, které nejsou v kolekci, která byla předána jako parametr operace operace kopie dvou kolekcí (copy) vytváří novou kolekci s prvky původní kolekce - jde o mělkou kopii!!!
Type Bag<T> nesetříděná kolekce prvků (pod)typu T, dovoluje duplicity pokud vkládaný prvek již v kolekci existuje, vloží se znovu operace mazání prvku z kolekce (remove) vymaže jeden výskyt prvku v kolekci operace změny prvku (update) změní všechny výskyt operace rozdílu, sloučení, průniku a kopie jsou stejné jako pro Set<T>
Type List<T> setříděná kolekce prvků (pod)typu T,dovoluje duplicity pořadí prvků v kolekci je dáno jejich pořadím při vkládání přehled o současné pozici (current_position) vkládání nastaví pozici na vložený prvek vkládání vloží prvek na současnou pozici mazání nastaví pozici na prvek přes smazaným
Type Array<T> jednodimenzionální pole proměnné délky pole se automaticky zvětší při vložení prvku mimo pole mazání prvku nastaví v poli na jeho pozici nil
ODL-Object definition language není programovací jazyk, jen jeho specifikace popisuje interface pro objekty v Objektovém Modelu ODMG cílem je zajistit přenositelnost databázových schémat mezi jednotlivými implementacemi ODBMS (v C++, Smalltalku) podporuje všechny konstrukce Objektového Modelu ODMG kompatibilní s Interface Definition Language (OMG IDL) rozšiřitelný jak pro budoucí funkcionality, tak pro optimalizace Data Definition Language pro objekty ODBMS
ODL - mapování
OQL - Object query language Základy OQL Dotazovaní Operátory Konverze Indexy
OQL - Object query language je založen na objektovém modelu ODMG je silně typovaný jazyk důvodem jeho vzniku je neefektivnost jazyka SQL na objektových databázích OQL je nadmnožina dotazovacího jazyka SQL, proto každý dotaz, který funguje nad relační databázi funguje i nad OQL OQL se na rozdíl od SQL jazyka nezabývá tvorbou datových struktur (například jako create table), jedná se o čistě dotazovací jazyk
OQL - Object query language OQL může být voláno přímo z programovacího jazyka pro který je definován ODMG binding (OQL může naopak volat funkce napsané v těchto jazycích) je využíván jako dotazovací jazyk v mnoha softwarových aplikacích existují různé implementace objektových databází, nad kterými vytváříme v OQL dotazy (EyeDB, O 2, ODABA...) OQL poskytuje primitiva pro práci s kolekcemi
OQL - Object query language Příklad volání OQL v jazyce Java OQLQuery oql; QueryResults results; db.begin(); // začátek tranzakce oql = db.getoqlquery("select p FROM Product WHERE Group=$1"); oql.bind(groupid); Product product results = oql.execute(); // zavolání dotazu s parametrami while (results.hasmore()) { product = (Product) results.next(); // operace nad objektem Product } results.close(); oql.close(); db.close(); // konec tranzakce
Konstrukce objektů v OQL množina: set(e 1, e 2,..., e n ) seznam: list(e 1, e 2,..., e n ) multi-množina: bag(e 1, e 2,..., e n ) pole: array(e 1, e 2,..., e n ) objekt třídy T: <T> (p 1 : e 1, p 2 : e 2,..., p n : e n ) Person (name: "Petr", age: 22) struktura: struct (p 1 : e 1, p 2 : e 2,..., p n : e n ) p i... název vlastnosti e i... výraz, který chceme dosadit do p i
Příklad objektu v C++ deklarace objektu v C++ class Person { public: d_string name; int age; d_set<d_ref<person>> friends; d_list<d_ref<person>> children; char* getname() { return name; } };
Dotazy Jednoduché dotazy zahrňují různé typy hodnot atomické hodnoty - 2 * 2, 10 + 3 strukturní hodnoty - User.name list, pole - User.children[0] volání metod - User.getName Objekt User se nazývá databázový vstupní bod. Operátor. (->) se smí použít jenom na jeden objekt, nikdy na kolekci objektů. User vrací celý objekt User typu Person.
Select... from... where SELECT - definuje strukturu výsledku na dotaz distinct a order by mění výslednou strukturu FROM - definice kolekcí kolekce join WHERE - definuje predikáty, které filtrují kolekce
Kolekce Set, Bag - nesetřídená množina dat select e from e in User.friends where e.name = "Peter" List, Array - setřídená kolekce dat User.children[1] User.children[1:2] [d_set<d_ref<person>> friends;] [d_list<d_ref<person>> children;]
Kolekce a nil testovaní na nil select x.name from x in User.friends where x!=nil and x.age > 18 OQL přeskakuje nil objekty proto select x.name from x in User.Friends where x.age > 18 je ekvivalentní předchozímu dotazu
Konstrukce výsledku dotazu Výsledkem dotazu může být multi-množina, množina, seznam nebo pole Implicitní forma je multi-množina(bag) po použití klíčového slova distinct vytváří výsledek jako množinu (Set) při použití třídění se výsledek vrací jako seznam (List)
Příklady select struct (friend: e.name, age: e.age) from e in User.friends select e.name, e.age (ekvivalentní s prvním dotazem) from e in User.friends select * from User.friends (* vrací všechny atributy prvku v kolekci)
Operátory Základní operátory setříděné od nejvyšší priority - (unární minus) *, / OR AND NOT =, <>, <, >, <=, >= +, - porovnání dvou objektů O1 = O2 je vždy FALSE. pro porovnání všech atributů se používá *O1 = *O2. komentáře v OQL jsou značeny pomocí -- nebo //
Operátory Základní operátory pro dotazování agregační operátory (count, min, max,...) Define Element Exists Group by Like Order by množinové operace (sjednocení, průnik,...)
Agregační operátory Count (určuje počet prvků vyhovujících dotazu) count (User.friends) návratovou hodnotou dotazu je integer Mezi další agregační operátory v OQL patří min (select e.age from e in User.friends) max (select x.age from x in User.children) sum (User.children) avg (select e.age from e in User.friends)
Operátory použití operátoru Exists name TheCompanies: list (Company) select c.name from c in TheComapnies where exists e in c.employees: e.age < 23 Použití operátoru Define a operátoru Like define MyFriends as select e from e in User.friends where e.name like "Sp*" (znovupoužitelné jenom v rámci jedné session)
Operátory Použití operátoru Element element ( select e from e in User.friends where e.name = "Jan Novák" ) Použití operátoru Order by select e from e in User.friends order by e.name, e.age výsledkem dotazu je vždy list, i když je zdrojem set
Operátor Group by seskupuje objekty kolekce se stejnou hodnotou jistých atributů select * from e in User.friends group by e.age Výsledkem tohoto dotazu je n-tice dvou-atributových struktur. Prvním atributem je atribut podle kterého agregujeme a druhým atributem je množina nazývána partition.
Operátor Group by příklad struktury výsledku bag(struct (age: real, partition: bag (struct (e: Person)))) využití operátorů s atributem partition select age, number: count (partition) from e in User.friends group by e.age vrací pro každou hodnotu age dvojici [age, počet přátel s věkem age]
Operátor Group by výsledek operátoru Group by je možné filtrovat při filtrovaní jsou vybrána jenom skupiny, které vyhovují podmínce v klauzule having select age, number: count (partition) from e in User.friends group by e.age having count(partition) > 1 vrací jenom skupiny, v kterých jsou aspoň dvě osoby se stejným věkem
Množinové operace standardní množinové operace jsou definovány na datových typech Set a Bag mezi množinové operace v OQL patří union (+)... sjednocení intersect (*)... průnik except (-)... rozdíl
Množinové operace define MyFriends as select m from m in User1.friends define YourFriends as select y from y in User2.friends příklad použití operace průnik pro zjištění společných přátel MyFriends * YourFriends
Operátor pick operátor pick je definován na typech Set a Bag vrací element kolekce je vybrán náhodně příklad pick (MyFriends)
Konverze OQL obsahuje několik operátorů sloužících na konverzi mezi některými datovými typy listtoset - slouží na konverzi seznamu nebo pole na množinu name Users : list (Person) //vytvoření kolekce uživatelů listtoset (User.children) intersect listtoset (Users[3].children)
Konverze Konverze množiny nebo multi-množiny na seznam pro vytvoření seznamu musíme množinu (multimnožina) setřídit select e from e in User.friends order by e.name vrací seznam setřídění podle jména pro případ, když nás nezajímá výsledné setřídění můžeme použít následující řešení select e from e in User.friends order by *
Konverze flatten - slouží na konverzi kolekce, která obsahuje další kolekce, na jednu velkou kolekci flatten (select distinct e.friends from e in Users) vrací množinu všech přátel uživatelů
Indexy index mapuje klíč na jeden nebo více elementů kolekce kdykoliv program vyhledává v kolekci podle klíče, systém používá index pro rychlejší nalezení elementu tento proces je pro uživatele transparentní přítomnost/nepřítomnost indexu neovlivňuje kód dotazu přístup pomocí indexu zaručuje konstantní čas přístupu nezávisle na velikosti kolekce
Indexy definice indexu create index MyFriends on age; následující dotaz bude díky definovanému indexu optimalizován select e from e in MyFriends where e.age > 18 and e.age < 30 display index - pomocí tohto příkazu jsme schopný vidět jak OQL využíva indexy při našich dotazech