Hauptseminar Datenbanksysteme - Datenbanken und XML Thema: Type-Checking OQL Queries In The ODMG Type Systems Angesprochene Punkte Allgemeines zum Type Checking in Datenbanksystemen Kurze Einführung in den ODMG Standard Formale Definitionen und Regeln Betrachtung von auftretenden Problemen und skizzieren von Lösungsvorschlägen Referenzen Type Checking (1/2) Es gibt zwei Möglichkeiten von Type-Checking Dynamisches type-checking während der Programmausführung Statisches type-checking, zur Kompilierzeit Type Checking (2/2) Aus folgenden Gründen wird statisches typechecking bei Datenbanken bevorzugt: Die Effizienz der Datenbank sollte nicht unnötig belastet werden Laufzeitfehler sind bei Datenbanken besonders kritisch „Message not understood“-Fehler werden durch statisches type-checking ausgeschlossen ODMG Standard (1/5) ODMG steht für Object Data Management Group (www.odmg.org) 1993 wurde der ODMG 1.0 Standard veröffentlicht; der aktuelle Stand ist Release 3.0 Dieser Vortrag geht noch auf den ODMG 2.0 Standard ein ODMG Standard (2/5) Interface Literal Class Interface: Definiert das abstrakte Verhalten eines Objektes Class: Ist ein erweitertes Interface mit einem Status Literal: Definiert nur einen abstrakten Status ODMG Standard (3/5) Was ist ein Interface? Ein Interface definiert das abstrakte Verhalten von Objekt-Typen. Ein Interface beinhaltet nur Methoden, keine Attribute. Beispiel (The top interface) interface Object { boolean same_as(in Object anObject); Object copy(); void delete(); }; ODMG Standard (4/5) Was ist eine Klasse? Eine Klasse ist ein erweitertes Interface. Eine Klasse definiert das abstrakte Verhalten und den abstrakten Zustand von Objekt-Typen. Beispiel (Class with extent) class Employee (extent employees) { attribute string name; attribute short id; attribute Department dept; float salary(); void hire(in Department d); void fire(); }; class Department (extent departments) { attribute string name; attribute short id; short NoOfEmployees(); }; ODMG Standard (5/5) Was ist ein Literal? Ein Literal definiert nur den abstrakten Zustand eines primitiven LiteralTypen. Es gibt keine Objektidentitäten für Literale Literal-Typen: -boolean -char -short -long -float -double -octet -string -user-defined collection, union and enumeration literale OQL- Queries Beispiel select well_paid(emp: x.name, sal: x.salary()) from employees as x where x.salary() > 50000 and x.dept.NoOfEmployees()>100 order by emp Das Resultat ist eine Menge vom Typ well_paid Der Typ well_paid ist vorher definiert und hat die Komponenten emp und sal Durch order by wird eine Liste von Objekten erzeugt Collection Objects (1/2) Es gibt verschiedene Typen von „Mengen“ Set<t> : Eine Menge ohne Duplikate Bag<t> : Eine Menge mit Duplikaten List<t> : Geordnete Menge Array<t> : Geordnete Menge mit Indizes Dictionary<t,v> : Menge aus Schlüsseln denen ein Wert zugeordnet wird Collection Objects (2/2) Interface Collection: Object { unsigned long cardinality(); boolean is_empty(); void insert_element(in any element); void remove_element(in any element); boolean contains_element(in any element); Iterator create_iterator(); }; Parametric polymorphism im ODMG Objektmodell any steht für jeden Objekttypen, dadurch ergeben sich auch weitere Probleme beim type-checking Die anderen Collection Types werden von diesem Interface abgeleitet Java vs. C++ Java unterstützt keinen parametrisierten Polymorphismus C++ bietet zu diesem Zweck Templates an interface Collection { int size(); boolean isEmpty(); void add(in Object element); boolean remove(in Object element); Iterator iterator(); ... }; interface Collection <T> { unsigned long cardinality(); boolean is_empty(); void insert_element(T element); void remove_element(T element); boolean contains_element(T element); Iterator <T> create_iterator(); }; Formale Spezifikation (1/2) Ein Schema ist eine Menge von Verknüpfungen Es beinhaltet Schlüsselwörter, die mit interfaces, classes, class extents und objects assoziiert sind Ein Schema ist wohlgeformt, wenn: jedes Schlüsselwort nur genau einer Zuordnung entspricht. der Typ zu jedem Objekt ebenfalls im Schema enthalten ist. bei interfaces und classes die Regeln für die Vererbung berücksichtigt wurden. Formale Spezifikation (2/2) Das Hinzufügen einer class extent zu einem Schema stellt ebenfalls den Namen des extent im Schema zur Verfügung. Ein Schema beinhaltet vordefinierte Zuordnungen String, int, boolean… Collection, Bag, Set, List, Array… die Datenbank-/Transaktionsklasse Vererbung (1/5) Das top interface ist „Object“, alle weiteren Interfaces werden von diesem abgeleitet Vererbung (2/5) Reflexivität Transitivität Vererbung (3/5) Substitution Ein Objekt vom Typ C2 kann ein Objekt vom Typ C1 ersetzen, falls C2 von C1 abgeleitet wird Die Regel beschreibt, daß im Ausdruck e ein vorkommendes y durch ein x ersetzt werden kann. Vererbung (4/5) Type casts Ist ein Ausdruck e vom Typ C1 und es gilt außerdem noch, dass C2 von C1 abgeleitet ist, ist ein type-cast möglich Es wird ein dynamisches type-checking benötigt Vererbung (5/5) Beispiel type casts class Person { (extent persons) ... } class Employee: Person { (extent employees) long salary(); ... } select well_paid(emp: x.name, sal:((Employee)x).salary()) from persons as x where ((Employee)x).salary() > 50000 Weitere Regeln zusammengefaßt Auf ähnliche Weise können nun auch Structures Interfaces Classes Objects and Messages in das Schema mit aufgenommen werden. OQL Queries and the ODMG object model (1/3) Nun kommen wir zu dem ersten negativen Beispiel für das type-checking: select well_paid(emp: x.name, sal: x.salary()) from employees as x where x.salary() > 50000 Employees ist vom Typ Collection x ist ein Objekt vom Typ any OQL Queries and the ODMG object model (2/3) Methoden für den Type any sind im ODMG Standard nicht definiert Es ist nicht möglich auf die Typkorrektheit von x.name und x.salary() zu schließen Theorem: OQL-Queries können nicht auf Typkorrektheit überprüft werden. OQL Queries and the ODMG object model (3/3) Beweis: select projection from e1 as x1, e2 as x2, … ,en as xn where e Die Variabel-Typen der xi müssen bestimmt werden Die Variabel-Typen der ei müssen bestimmt werden Im besten Fall nehmen wir an, daß die ei vom Typ Collection sind Folglich sind die xi vom Typ any OQL Queries and Java (1/5) Die bisherigen Probleme beruhen auf dem Type any im ODMG Type-System In der Java-Anbindung ist der Type Object das Wurzel-Objekt Alle Objekte im Java-Typ-System erben die Eigenschaften des Wurzel-Objektes OQL Queries and Java (2/5) Theorem: Statisches Type-checking ist im JavaType-System nicht möglich Beweis Der Typ der Variable x wird nun als Objekt identifiziert Nur Methoden aus dem Interface „Object“ können benutzt werden Das type-checking schlägt fehl sobald unbekannte Methoden aufgerufen werden OQL Queries and Java (2/5) Beispiel class Professor { public float salary() { } ... } class Course { public int enrollment() { } ... } Collection professors; Collection courses; select x from professors as x, x.courses() as y where x.salary() > 70000 and y.enrollment() > 50 OQL Queries and Java (3/5) x.salary(), x.courses() und y.enrollment() werden stets als nicht typkorrekt klassifiziert Hier stellt sich die Frage ob sich Java für die Datenbankprogrammierung eignet? Betrachten wir zunächst eine Lösung für dieses Problem – dynamisches type-checking… OQL Queries and Java (4/5) OQL Query with type casts Theorem: Bei ausdrücklicher Typangabe für jede Variabel innerhalb der Anfrag im Java-TypSystem ist ein type-checking möglich, allerdings nur auf Kosten des teuren Checks zur Laufzeit (ohne Beweis) OQL Queries and Java (5/5) Beispiel Collection professors; Collection courses; select x from professors as (Professor)x, x.courses() as (Course)y where x.salary() > 70000 and y.enrollment() > 50 Diese Anfrage ist aufgrund des type-casts möglich Es wird ein Check zur Laufzeit ausgeführt OQL Queries and C++ (1/2) Theorem: Ein Type-System, das parametrisierten Polymorphismus unterstützt erlaubt statisches typechecking von OQL Queries Beweis: Dieses Resultat wird erziehlt, da zur Kompilierzeit jedem Collection-Type ein bestimmter Type zugeordnet wird. Dadurch wird jeder ElementType eindeutig einer Menge zugeordnet. Die Variablen einer Anfrage gehören einem spezifischen Types an OQL Queries and C++ (2/2) Beispiel in C++ Collection <Professor> professors; Collection <Course> courses; select x from professors as x, x.courses() as y where x.salary() > 70000 and y.enrollment > 50 Korrolar: Das Type-System von C++ erlaubt statisches type-checking von OQL Queries OQL Queries with Order by (1/2) Eine Anfrage in allgemeiner Form: select projection from e1 as x1, e2 as x2, … ,en as xn where e order by e´1, e´2, … , e´m Auch hier treten die schon bekannten Probleme auf Ein Vergleich von zwei Objekten kommt hinzu OQL Queries with Order by (2/2) Theorem: Bei expliziter Typangabe für jede Variabel innerhalb der Anfrage mit Order by Klausel im Java-Typ-System ist ein type-checking möglich, allerdings wiederum nur zur Laufzeit Theorem: Ein Type-System, das parametrisierten Polymorphismus unterstützt erlaubt statisches type-checking von OQL Queries mit Order by Klausel Java OQL (1/6) Java OQL ist eine Untersprach von Java und ermöglicht eine leichtere Anbindung an die Datenbank Es gibt zwei Formen dieser Vereinfachung durch Methoden durch Klassen Java OQL (2/6) Zunächst die Möglichkeit durch Methoden interface DCollection extends java.util.Collection { Object selectElement(String predicate) java.util.Iterator select(String predicate) DCollection query(String predicate) boolean existsElement(String predicate) } Die anderen Interfaces aus dem ODMG Standard (DSet, DBag, DList …) werden von diesem Interface abgeleitet Java OQL (3/6) Ein Java OQL Query DCollection bestPaid; bestPaid = employees.query( „for all x in employees: this.salary() >= x.salary()“ ); Das obige Beispiel findet die Menge der bestbezahltesden Mitarbeiter Java OQL (4/6) Die Anfrage wird mittels eines Strings gestellt Type-checking im Java-Type-System ist stets möglich, unabhängig vom Stringinhalt Der String muß während der Laufzeit ausgewertet werden Theorem: Das type-system von Java kann mit Java-OQL-Queries nicht umgehen, so daß ein type-checking nicht möglich ist Java OQL (5/6) Java OQL Queries als Klassen class OQLQuery { // Java constructors OQLQuery create(String query); void bind(Object parameter); Object execute(); } DBag selectedEmployee; OQLQuery query = new OQLQuery(); query.create(„select well_paid(emp: x.name, sal: x.salary()) from employees as x where x.salary() > $1 and x.dept.NoOfEmployees() > $2“); query.bind(50000); query.bind(100); selectedEmployees = (DBag) query.execute(); Java OQL (6/6) Es werden gut bezahlte Mitarbeiter in großen Abteilungen gesucht Bei diesem Beispiel treten mehrere Probleme auf: Es kann nur ein Laufzeitcheck ausgeführt werden Die Übergabeparameter (mittels query.bind()) müssen zu dem Query passen Der Rückgabewert von query.execute() ist Object, die Select-Anweisung liefert eine Menge von Objekten C++ und OQL-Erweiterung Auch für C++ gibt es eine Erweiterung für die vereinfachte Anbindung an die Datenbank Die in C++ zur Verfügung stehenden Templates helfen hier auch nicht Die Queries werden als String gegeben… Beim type-checking sind Strings stets typkorrekt C++ unterliegt den selben Problemen, die eben im Java-Typ-System diskutiert wurden Geordnete Mengen (1/2) Weder im ODMG-Standard noch im Java oder C++ Type-System können geordnete Menge auf Typkorrektheit geprüft werden Ein Beispiel im ODMG Object Model interface Ordered_Collection: Collection { unsigned long cardinality(); boolean is_empty(); void insert_element(in Ordered element); void remove_element(in Ordered element); boolean contains_element(in Ordered element); Iterator create_iterator(); } Geordnete Mengen (2/2) Das Interface Ordered_Collection erbt von Collection Die Vererbungsregeln wurden bei den folgenden Funktionen nicht befolgt insert_element remove_element contains_element Die Funktionsköpfe (die Aufrufparameter) dieser Funktionen wurden geändert Bounded Type Quantification Theorem: Ein Type-System, das bounded type quantificatien unterstützt und das top-Object beinhaltet kann geordnete Mengen auf Typkorrektheit überprüfen interface Ordered_Collection <T: Ordered>: Collection <T>{ ... } Eiffel unterstützt diese Methode, doch C++ benötigt eine klare Vererbungsstruktur F-Bounded polymorphism (1/3) Theorem: Wenn die C++-Anbindung an die Datenbank F-bounded polymorphism unterstützt ist ein statisches type-checking von Queries möglich interface Ordered_Collection <T: Ord_element <T>> :Collection <T>{ ... } F-Bounded polymorphism (2/3) Beispiel interface Employee { String name; short id: //boolean leq(Employee e); } Dieses Interface entspricht nicht den Vererbungsregeln, da Employee nicht von Ord_element <Employee> abgeleitet wird F-Bounded polymorphism (3/3) interface Ord_element <Employee> { boolean leq(Employee e); } Durch das obige Interface werden die Vererbungsstrukturen wiederhergestellt Es wird garantiert, daß die Methoden die richtige Signatur haben Statisches Type-checking ist möglich Zusammenfassung OQL Queries können im ODMG-Standard nicht auf Korrektheit geprüft werden OQL Queries können in der Java-Anbindung nicht auf Korrektheit überprüft werden Parameter Polymorphismus sollte von einer Sprache für die Datenbank unterstüzt werden Um geordnete Menge korrekt zu überprüfen wird F-bounded polymorphism benötigt Referenzen Type-Checking OQL Queries In The ODMG Type System Suad Alagic – Wichita State University ACM Transaction on Database Systems, Vol.24, No. 3 September 1999, Page 319-360 The Object Data Standard ODMG 3.0 R.G.G. Cattell, Douglas Barry, Mark Berler, Jeff Eastman, David Jordan, Craig Russell, Olaf Schadow, Torsten Stanieda Fernando Velez Verlag: Morgan Kaufmann Publishers ISBN: 1-55860-647-5