RHEINISCHE FRIEDRICH-WILHELMS-UNIVERSITÄT BONN INSTITUT FÜR INFORMATIK III Diplomarbeit Implementierung eines objektorientierten Datenmodells mit deduktiven Regeln in Oracle8 Andrea Scheuber Michael Horn 5. November 1999 Erstgutachter: Prof. Dr. Rainer Manthey Danksagung An dieser Stelle möchten wir uns bei einigen Menschen bedanken: Unserem Betreuer, Prof. Dr. Rainer Manthey, danken wir für die vielen Stunden, die er mit der Betreuung unserer Diplomarbeit verbracht hat. Andreas Behrend danken wir für die hilfreiche Unterstützung bei der Lösung von Prolog- und Oracle-Problemen. Bei Stefan Schubert möchten wir uns für seine hervorragende Installationsanleitung und FAQ-Seite zum Thema CPT und für die gemeinsame Einarbeitung in den Quellcode des CPT bedanken. Für die hilfreichen und prompten Kommentare beim Korrekturlesen dieser Arbeit danken wir Arno Bücken. Inhaltsverzeichnis Inhaltsverzeichnis 1 Einleitung (Andrea Scheuber und Michael Horn) ............................................................... 5 2 Chimera (Michael Horn) .................................................................................................... 7 2.1 Das Datenmodell von Chimera ................................................................................... 8 2.1.1 Konzepte eines Chimera-Schemas ...................................................................... 9 2.1.1.1 Value Types.................................................................................................... 9 2.1.1.2 Value Classes................................................................................................ 10 2.1.1.3 Object Classes............................................................................................... 10 2.1.1.4 Chimera Views ............................................................................................. 12 2.1.1.5 Constraints.................................................................................................... 12 2.1.1.6 Trigger.......................................................................................................... 14 2.1.2 Klassenhierarchien und Vererbung in Chimera ................................................. 15 2.2 Deklarative Ausdrücke von Chimera ........................................................................ 17 2.2.1 Anwendung deklarativer Ausdrücke ................................................................. 19 2.3 Imperative Ausdrücke von Chimera.......................................................................... 22 3 Das Chimera Prototyping Tool (Michael Horn) ................................................................ 26 3.1 Architektur des CPT................................................................................................. 27 3.2 Der Bonner Chimera-Dialekt .................................................................................... 29 3.2.1 Unterschiede zwischen Chimera- und CPT-Datenmodell .................................. 30 3.2.2 Unterschiede bei deklarativen und imperativen Ausdrücken.............................. 31 3.3 Abbildung des objektorientierten Datenmodells nach Phoenix.................................. 31 3.3.1 Werteklassen und -typen................................................................................... 34 3.3.2 Objektklassen und Klassenhierarchien .............................................................. 35 3.3.3 Integritätsbedingungen...................................................................................... 38 4 Oracle8 (Andrea Scheuber) .............................................................................................. 40 4.1 Datenbanksysteme und Datenmodelle....................................................................... 40 4.2 Die relationalen Konzepte von Oracle8..................................................................... 42 4.2.1 Built-in-Datentypen .......................................................................................... 42 4.2.2 Tabellen............................................................................................................ 44 4.2.3 Sichten.............................................................................................................. 44 4.2.4 Integritätsbedingungen...................................................................................... 45 4.2.5 Trigger.............................................................................................................. 46 4.2.6 Interne Prozeduren und Funktionen................................................................... 47 4.2.7 Externe Prozeduren und Funktionen.................................................................. 49 4.3 Die objektorientierten Konzepte von Oracle8 ........................................................... 49 4.3.1 Objekttypen ...................................................................................................... 50 4.3.1.1 Interne Verwaltung eines Objekttyps als Wertebereich eines Attributs .......... 50 4.3.1.2 Methoden...................................................................................................... 52 4.3.1.3 Die Vergleichsfunktionen MAP und ORDER ............................................... 53 4.3.2 Kollektionstypen............................................................................................... 53 4.3.3 Objekttabellen................................................................................................... 55 4.3.4 Referenzierte Spalten........................................................................................ 55 4.3.5 Objektsichten.................................................................................................... 56 4.4 SQL-92-Standard-Erweiterungen von Oracle8.......................................................... 57 3 Inhaltsverzeichnis 4.4.1 4.4.2 4.4.3 4.4.4 4.4.5 Zusätzliche Datentypen unter Oracle8............................................................... 57 Erweiterte und neue Funktionen in Oracle8....................................................... 58 Pseudospalten ................................................................................................... 58 Zusätzliche Operatoren ..................................................................................... 59 Zusätzliche Konzepte........................................................................................ 59 5 Eine Oracle-basierte Implementierung des Chimera Prototyping Tool (Andrea Scheuber und Michael Horn) ........................................................................................................... 62 5.1 Architektur des CPTOracle .......................................................................................... 62 5.1.1 Einlesen eines Chimera-Schemas (load_schema/1) .................................... 65 5.1.2 Anlegen einer Chimera-Datenbank (chimera_createdb/1) ...................... 66 5.1.3 Öffnen einer Chimera-Datenbank (chimera_opendb/1) ............................. 67 5.1.4 Schließen einer Chimera-Datenbank (chimera_closedb/0) ...................... 67 5.1.5 Löschen einer Chimera-Datenbank (chimera_destroydb/0).................... 68 5.2 Das ECLiPSe-Oracle-Interface .................................................................................. 68 6 Übersetzung von Chimera-Schemata in Oracle8-SQL-Schemata (Andrea Scheuber) ........ 74 6.1 Datentypen ............................................................................................................... 74 6.2 Wertetypen............................................................................................................... 75 6.3 Werteklassen ............................................................................................................ 77 6.4 Objektklassen und Klassenhierarchien...................................................................... 78 6.4.1 Abbildung von Chimera-Objektklassen auf Oracle8-Tabellen........................... 79 6.4.2 Abbildung einer Chimera-Klassenhierarchie auf Oracle8-Sichten ..................... 80 6.4.3 Umsetzung von DML-Operationen auf Sichten................................................. 84 6.4.4 Abgeleitete Objektklassen................................................................................. 88 6.5 Vergleich zum CPTPhx-Ansatz .................................................................................. 91 6.6 Unterschiede zwischen CPTPhx und CPTOracle............................................................ 93 7 Übersetzung deklarativer Ausdrücke (Michael Horn) ................................................... 94 7.1 Konzepte der Übersetzung deklarativer Ausdrücke nach SQL .................................. 94 7.2 Implementierung ...................................................................................................... 98 7.3 Modifikationen und Optimierungen........................................................................ 101 7.4 Unterschiede zwischen CPTPhx und CPTOracle.......................................................... 103 8 Übersetzung imperativer Ausdrücke (Andrea Scheuber)............................................. 104 8.1 Transaktionen......................................................................................................... 104 8.2 Das Transaktionskonzept von Chimera................................................................... 105 8.3 Erzeugung und Verwaltung von Variablenbindungen ............................................. 109 8.4 Übersetzung von Anfragen ..................................................................................... 110 8.5 Übersetzung von DML-Operationen....................................................................... 113 9 Zusammenfassung und Ausblick (Andrea Scheuber und Michael Horn)..................... 119 10 Literaturverzeichnis.................................................................................................... 125 4 Inhaltsverzeichnis Andrea Scheuber und Michael Horn 1 Einleitung Heutzutage existieren in der Datenbankforschung eine Vielzahl von unterschiedlichen Datenmodellen, von denen sich das relationale und einige der unterschiedlichen objektorientierten Modelle kommerziell durchgesetzt haben. Da der Ansatz zur Objektorientierung in letzter Zeit nicht nur bei Programmiersprachen, sondern auch bei Datenbanksystemen zu beobachten ist, wurde die relationale Datenbanktheorie durch objektorientierte Konzepte erweitert. Das Ziel dieser Erweiterungen ist es, mächtigere Konzepte für die Datenmodellierung zu erhalten. Zusätzlich zu objektorientierten Erweiterungen sind aktive und deduktive Regeln als zusätzliche Konzepte eingeführt worden. Die Integration von Regeln in die Datenbankmanagementsysteme soll eine zentrale Verwaltung der "Anwendungslogik" von Applikationen ermöglichen. Unterschiedliche Anwendungen können dadurch auf identische Funktionalitäten zurückgreifen und Redundanzen im Quellcode vermieden werden. Im Rahmen dieser Forschungen ist das Projekt IDEA (Intelligent Database Environment for advanced Applications) unter der Schirmherrschaft der Europäischen Union entstanden. Ein Ergebnis dieses Projekts ist das Datenmodell Chimera ([CM93]). Bestandteil von Chimera sind unter anderem eine Datendefinitions- und Datenmanipulationssprache, die sowohl deduktive als auch objektorientierte Konzepte unterstützt. Zusätzlich ist es in Chimera möglich, aktive Regeln zu definieren. Aus diesem Grund kann Chimera als ein deduktives objektorientiertes Datenmodell mit aktiven Komponenten bezeichnet werden. Auf der Grundlage dieses Datenmodells wurde an der Universität Bonn das Chimera Prototyping Tool (CPT) entwickelt ([GL96 und GLM96]). Das CPT ist ein akademisches Datenbankmanagementsystem, welches die Funktionalitäten des Datenmodells von Chimera umsetzt. Die Implementierung des CPT basiert auf dem universitären, aktiven, relationalen Datenbankmanagementsystem Phoenix. Sowohl Phoenix als auch das CPT sind in ECLiPSe-Prolog realisiert worden. Aufgabe dieser Diplomarbeit ist die Implementierung des Datenmodells von Chimera auf der Basis von Oracle8. Sie beschäftigt sich mit der Übersetzung von Chimera-Schemata in Oracle8-Schemata, wobei die interessanten Aspekte in der Übersetzung der ChimeraKlassenhierarchien und der Übersetzung der Chimera-Datenmanipulationssprache liegt. 5 Inhaltsverzeichnis Oracle8 ist aus mehreren Gründen für diese zweite Implementierung ausgewählt worden. Das objekt-relationale Datenbanksystem Oracle8 ist eines der am weitesten verbreiteten kommerziellen Datenbanksystem. Des weiteren stellt Oracle8 objektorientierte Konzepte zur Verfügung, die auf den ersten Blick zur Realisierung eines objektorientierten Datenmodells geeignet erscheinen. Das Ziel dieser Diplomarbeit ist es, ein leistungsfähigeres System zu entwickeln, welches ein größeres Datenvolumen unterstützt, als es die bisherigen Implementation basierend auf Phoenix kann. Die neue Implementierung wurde ebenfalls in ECLiPSe-Prolog realisiert und verwendet Teile der bestehenden Implementierung. Die Verbindung zwischen dem ECLiPSeSystem und dem Oracle8-Datenbankserver wird durch die ECLiPSe-Oracle Schnittstelle von Thomas Kolbe ([Kol95]) hergestellt. Basierend auf den wenigen bisherigen Tests, erfüllt die neue Implementierung des CPT die gewünschten Anforderungen nicht vollständig, da die verwendete Schnittstelle zwischen Prolog und Oracle8 nicht die benötigte Leistungsfähigkeit besitzt. Die vorliegende Arbeit ist wie folgt strukturiert worden: Die Kapitel 2-4 führen die Grundlagen ein, die zum Verständnis der Arbeit notwendig sind. Kapitel 2 stellt das Datenmodell von Chimera vor. Kapitel 3 geht auf die IDEA-Methodologie ein. Kapitel 4 stellt das objektrelationale Datenbanksystem Oracle 8 vor. Die Kapitel 5-8 beschäftigen sich mit der Oracle8basierten Umsetzung des Chimera-Datenmodells, wobei Kapitel 5 auf dessen Architektur eingeht. In Kapitel 6 beschäftigt sich mit der Abbildung einer Chimera-Schemadefinition in eine Oracle8-Schemadefinition. Kapitel 7 beschäftigt sich mit der Übersetzung von deklarativen Ausdrücken. Kapitel 8 geht auf die Übersetzung der Operationen zur Datenmanipulation ein. 6 Inhaltsverzeichnis Michael Horn 2 Chimera Das Ziel des IDEA-Projektes (http://www.txt.it/idea/idea.html) war die Schaffung einer intelligenten Datenbankumgebung für erweiterte Applikationen ("Intelligent Database Environment for Advanced Applications"). Die Arbeiten im Rahmen dieses Projektes fanden zwischen Juni 1992 und März 1997 statt. Die Mitglieder des IDEA Projektes stammten aus der Industrie und der Forschung; darunter befanden sich auch das Politecnico di Milano und die Rheinische Friedrich-Wilhelms-Universität Bonn. Im Rahmen dieses Projektes wurde Chimera entwickelt, ein objektorientiertes Datenmodell mit einer dazugehörigen Datendefinitionssprache (DDL) und einer Datenmanipulationssprache (DML). In der griechischen Mythologie ist eine Chimäre ein Monster mit drei Köpfen: einem Löwenkopf, einem Ziegenkopf und einem Schlangenkopf. Die drei verschiedenen Köpfe dieses Fabelwesens symbolisieren die drei verschiedenen Konzepte von Chimera: • Objektorientierung: Das Datenmodell von Chimera unterstützt alle wesentlichen Konzepte der Objektorientierung. Daten werden in Klassen organisiert, die wiederum in Klassenhierarchien strukturiert werden können. In Klassenhierarchien sind Vererbung und Redefinition zugelassen. • Deduktive Regeln: Deduktive Regeln werden zur Datengewinnung eingesetzt. Eine einfache Variante von deduktiven Regeln sind Sichten im relationalen Datenmodell. Mit Hilfe von deduktiven Regeln können aber auch Integritätsbedingungen und Populationsregeln definiert werden. Das Datenmodell von Chimera unterstützt sowohl Klassenpopulationsregeln als auch Attributdefinitionsregeln. Aufgrund ihrer Verwendung werden deduktive Regeln auch als passive Regeln bezeichnet. • Aktive Regeln: Aktive Regeln reagieren auf Zustandsveränderungen der Datenbank. Zustandsveränderungen können hierbei Anfragen oder Änderungen des Datenbestandes, Zeitereignisse oder beliebige externe Ereignisse sein. Das Chimera-Modell unterstützt nur 7 Inhaltsverzeichnis Reaktionen auf Zustandsveränderungen des Datenbestandes und Aufrufe von Operationen. Aktive Regeln werden auch Trigger genannt. Die folgenden Abschnitte beschreiben den Funktionsumfang des "reinen" Chimera-Modells und basieren auf dem Buch von Stefano Ceri und Piero Fraternali ([CF97]). Im Zuge der Weiterentwicklung und der Implementierung lauffähiger Systeme sind einige Veränderungen vorgenommen worden. Die Unterschiede und Einschränkungen der Bonner Implementation werden in Kapitel 3 vorgestellt. 2.1 Das Datenmodell von Chimera Chimera basiert auf einem objektorientierten Datenmodell. Zur Definition eines ChimeraSchemas können folgende Konzepte verwendet werden: • Wertetyp ("value type") • Werteklasse ("value class") • Objektklasse ("object class") • Sicht ("view") • Integritätsbedingung ("constraint") • aktive Regeln ("trigger") Bei Schemakonzepten unterscheidet man zwischen extensionalen und abgeleiteten Konzepten. Unter extensionalen Konzepten versteht man Konzepte, deren Daten in einer Datenbank physikalisch abgespeichert werden. Die Daten werden materialisiert. Abgeleitete Konzepte kombinieren bereits vorhandene Daten zu neuen Daten, die allerdings nicht abgespeichert werden: Daten abgeleiteter Konzepte werden erst auf Anfrage hin berechnet bzw. hergeleitet. Hierbei ist zu beachten, daß dies in der Art der relationalen Sichten geschehen kann oder aber auch durch Berechnungsformeln, die aus bestehenden Daten, neue ableiten. "Value types" und "value classes" gehören hierbei zu den extensionalen Konzepten. "Object classes" gibt es sowohl als extensionale also auch abgeleitete Konzepte. Das Chimera-Modell erlaubt bei "object classes" auch Mischformen (siehe Abschnitt 2.1.1.3). "Views" und "constraints" gehören nur zu den abgeleiteten Konzepten. "Trigger" gehören weder zu den extensionalen noch zu den abgeleiteten Konzepten, da sie auf Ereignisse, z.B. Veränderungen im Datenbestand einer Datenbank, reagieren. Jeder "value type", "value class" usw. muß mit einem identifizierenden Namen ausgestattet werden. Chimera erlaubt hierbei nur Namen, die mit einem kleinen Buchstaben beginnen. 8 Inhaltsverzeichnis 2.1.1 Konzepte eines Chimera-Schemas 2.1.1.1 Value Types Unter einem "value type", zu deutsch einem Wertetyp, versteht man einen Datentyp, der zur Definition von Parametern für Operationen und Attribute benutzt werden kann. Der große Vorteil der Wertetypen ist die flexible Definition. Jeder Entwickler einer Chimera-Datenbank kann zwischen den klassischen atomaren Datentypen und selbstdefinierten Wertetypen wählen. Auch die internen Basisdatentypen sind als "value type" definiert worden. Folgende homogenen Datentypen stehen einen Entwickler zur Verfügung: • integer • boolean • real • string Wertetypen bieten die Möglichkeit, obige Basisdatentypen zu verfeinern und neu zu strukturieren. Chimera bietet drei Konzepte, mit deren Hilfe eigenständige, komplexe Datentypen strukturiert werden können: • Liste ("list-of"): Mit Hilfe dieses Konstruktes können Attribute Listen beliebiger Länge beinhalten. Listen dürfen dabei durchaus auch doppelt vorhandene Elemente beinhalten. • Menge ("set-of"): Im Gegensatz zu Listen, dürfen Mengen keine Duplikate enthalten und die Elemente sind untereinander nicht geordnet. • Tupel ("record-of"): Mit Hilfe eines Tupeldatentyps können Attribute eine feste Struktur bekommen. Die Struktur des Datentyps wird bei der Definition fest vorgegeben. Chimera besitzt eine offene Architektur für "value types". Wertetypen können beliebig ineinander verschachtelt und rekursiv miteinander verbunden werden. Zu jedem Datentyp können Integritätsbedingungen definiert werden. Integritätsbedingungen bieten in diesem Zusammenhang die Möglichkeit, den Wertebereich eines Datentyps einzuschränken. Sie bieten zum Beispiel die Möglichkeit, einen Datentyp für gerade Zahlen zu definieren indem man über eine Integritätsbedingung alle ungeraden Zahlen als Wert für diesen Datentyp ausschließt. Folgendes kleine Beispiel zeigt einen selbstdefinierten Datentyp um ein Datum abzuspeichern: define value type datum: record-of(tag:integer, monat:integer, jahr:integer) end; Über Integritätsbedingungen könnte man den Wertebereich der obigen Struktur so einschränken, daß es nur vierstellige Jahresangaben mit maximal zwölf Monaten mit jeweils maximal 31 Tagen gibt. Die Sonderregeln für jeden einzelnen Monat inklusive der Schaltjahre können ebenfalls für jeden Monat gesondert definiert werden. 9 Inhaltsverzeichnis 2.1.1.2 Value Classes Auch eine "value class" ist ein Datentyp. Der Unterschied zwischen einer Werteklasse und einem Wertetyp ist die Art und Weise der Definition der zulässigen Werte. In einem Wertetyp wird nur die Struktur des Datentyps festgelegt, der Wertebereich eines Wertetypen ist also (unendlich) groß und nicht veränderbar (z.B. ganze Zahlen, beliebige Zeichenketten beliebiger Länge). Eine Werteklasse hingegen legt zusätzlich zur Struktur des Datentyps die endliche Anzahl der Elemente der Klasse explizit fest. Eine Werteklasse entspricht also einem Aufzählungsdatentyp: define value class geschlecht: string end; Für Werteklassen existieren zwei besondere Datenmanipulationsbefehle "add" und "drop": add (geschlecht, "maennlich"); add (geschlecht, "weiblich"); add (geschlecht, "male"); drop(geschlecht, "male"); "add" fügt einen neuen Wert in die Werteklasse ein, "drop" löscht einen vorhandenen Wert aus einer bestehenden Klasse. 2.1.1.3 Object Classes Die Objektklasse ist das zentrale Konzept des Chimera-Modells. Die Definition einer Objektklasse legt die Struktur (Attribute) und die Ausprägungen (Integritätsbedingungen, Trigger und Operationen) der zu speichernden Objekte fest. Jede Instanz einer Objektklasse wird durch einen systemweit eindeutigen Objektidentifikator (OID) bezeichnet. Ein Objekt in Chimera ist eine Instanz einer Objektklasse. Ein Objekt muß alle Integritätsbedingungen der Objektklasse und der dazugehörigen Datenbank erfüllen. Durch die Zugehörigkeit eines Objektes zu einer Objektklasse können alle zur jeweiligen Klasse gehörenden Operationen auf dieses Objekt angewendet werden. Objektklassen können mit Hilfe folgender Klassenkonzepte definiert werden. Für die Definition einer Objektklasse ist zu beachten, daß die Konzeptnamen immer im Plural verwendet werden müssen: • "superclasses": Das erste Konzept, das bei einer Klassendefinition verwendet werden kann dient dazu, Klassenhierarchien abzubilden. Die Möglichkeiten von Klassenhierarchien werden in Abschnitt 2.1.2 erläutert. • "attributes": Jede Objektklasse benötigt Attribute. Attribute können entweder in einer Klasse lokal definiert werden oder aber von einer Oberklasse vererbt werden. Das Thema der Vererbung wird ebenfalls in Abschnitt 2.1.2 erläutert. Ein Attribut besteht aus einem Namen und einem Wertebereich. Als Datentyp sind hierbei alle Wertetypen und Werteklassen zulässig. Des weiteren besteht die Möglichkeit, einem Attribut als Wertebereich eine Objektklasse zuzuweisen. 10 Inhaltsverzeichnis • "constraints": Constraints, zu deutsch Integritätsbedingungen, definieren illegale Zustände der Datenbank. Jede Objektklasse kann eigene Integritätsbedingungen festlegen, die illegale Zustände innerhalb der Population einer Klasse ausschließen. Weitere Erläuterungen und Beispiele für Integritätsbedingungen stehen in Abschnitt 2.1.1.5. In Chimera existieren zusätzlich zu den frei definierbaren Integritätsbedingungen noch drei grundlegende Integritätsbedingungen: key, unique und notnull. Die ersten beiden Arten von Integritätsbedingungen werden durch ein separates Schlüsselwort in der Definition einer Objektklasse ausgedrückt. Mit Hilfe dieser beiden Schlüsselworte können sowohl Primär- als auch Sekundärschlüssel für eine Objektklasse definiert werden. Die dritte Integritätsbedingung kann während der Definition eines Attributes verwendet werden: notnull legt fest, daß dieses Attribut in jedem Objekt mit einem Wert belegt werden muß. • "operations": Operationen können für Attribute definiert werden. Operationen führen Manipulationen an einzelnen Attributwerten durch. Operationen ermöglichen zum Beispiel das Alter einer Person jederzeit basierend auf dem aktuellen und dem Geburtsdatum zu berechnen. Für jede Objektklasse werden automatisch die Operationen für Datenmanipulation (create, delete und modify) und Anfragen (select und display) erstellt. Die Anwendung dieser automatisch erzeugten Operationen wird in Abschnitt 2.2.1 erläutert. • "triggers": Trigger definieren Aktionen, die in einer bestimmten Situation ausgeführt werden sollen. Die Trigger einer Objektklasse können nur dann ausgelöst werden, wenn Veränderungen im Datenbestand der jeweiligen Klasse geschehen. Genauere Erläuterungen bzgl. Trigger werden in Kapitel 2.1.1.6 gegeben. Folgendes kleine Beispiel soll die Syntax der Definition einer Objektklasse verdeutlichen: define object class adresse attributes strasse: string, plz: number, wohnort: string end; define object class person attributes name: string notnull, vorname: string notnull, geschlecht: geschlecht, adresse: adresse key (name, vorname) end; Neben den bisher vorgestellten extensionalen Objektklassen und Attributen existieren in Chimera noch abgeleitete Objektklassen ("derived object classes") und Attribute ("derived attributes"). Abgeleitete Objektklassen entsprechen eingeschränkten Sichten des relationalen Datenmodells. Die Definition von abgeleiteten Objektklassen ist auf Attribute der Oberklas11 Inhaltsverzeichnis sen der jeweiligen Klassenhierarchie beschränkt. Im Gegensatz zu relationalen Sichten können also nicht beliebige Kollektionen und Kombinationen von Werten zusammengestellt werden (vgl. Chimera Sichten in Abschnitt 2.1.1.4). Daten einer abgeleiteten Klasse werden über Populationsregeln aus extensionalen oder abgeleiteten Klassen und Attributen hergeleitet. In abgeleiteten Klassen dürfen keine zusätzlichen extensionalen Attribute definiert werden, da abgeleitete Klassen ansonsten materialisiert, also permanent gespeichert werden müßten. Abgeleitete Attribute werden mit Hilfe von Regeln definiert. Definitionsregeln werden mit Hilfe beliebiger deklarativer Ausdrücke formuliert. Im Gegensatz zu Populationsregeln für abgeleitete Objektklassen, müssen Attributdefinitionsregeln nicht ausschließlich auf Attributen der jeweiligen Klassenhierarchie basieren. Bei der Definition von Klassenhierarchien werden abgeleitete Attribute genauso wie extensionale Attribute an alle Unterklassen vererbt. Die Definition von abgeleiteten Attributen kann im Rahmen einer Klassenhierarchie verändert werden. Das Aussehen und die Möglichkeiten von Populationsregeln für abgeleitete Klassen und Definitionsregeln für abgeleitete Attribute, sowie der Redefinition von Regeln für abgeleitete Attribute wird in Abschnitt 2.2 erläutert. 2.1.1.4 Chimera Views Sichten (engl. view) in Chimera stellen ein Nischenkonzept dar. Die Elemente von Chimera Sichten sind keine Objekte mehr, da sie die Eigenschaften von unterschiedlichen Klassen, die nicht zu einer Klassenhierarchie gehören müssen, vereinigen können. Da die Datensätze einer Sicht keine Objekte darstellen, besitzen sie auch keinen Objektidentifikator (OID). Bei der Definition einer Sicht können Attribute aller im Schema vorhandenen Objektklassen verwendet werden: Sichten stehen immer außerhalb einer Klassenhierarchie. Chimera Sichten übernehmen die Funktion von vordefinierten Anfragen an den Datenbestand einer Chimera Datenbank. Die Verwendung von Sichten ist besonders interessant in Verbindung mit der Negation innerhalb deklarativer Ausdrücke. Deklarative Ausdrücke (siehe Abschnitt 2.2) bestehen aus Konjunktionen. Mit Hilfe von Sichten und Negationen können nun aber auch Disjunktionen ausgedrückt werden. Um die Definition von Chimera-Sichten zu vereinfachen, wurden die möglichen Wertebereiche eingeschränkt: Attribute von Sichten dürfen nur mit Hilfe atomarer und Tupeldatentypen definiert werden. Die Definition von Sichten in Chimera basiert auf deduktiven Regeln, die mit Hilfe deklarative Ausdrücke formuliert werden können (siehe Abschnitt 2.2). 2.1.1.5 Constraints Jeder Datenbankzustand muß alle Integritätsbedingungen erfüllen. Eine Integritätsbedingung entspricht einer Bedingung, die nur im Fehlerfalle erfüllt werden darf. Im Chimera-Modell werden "constraints" als Sichten angesehen. Falls eine Integritätsbedingung durch einen Da12 Inhaltsverzeichnis tenbankzustand verletzt wird, kann mindestens ein Datensatz für eine solche Sicht hergeleitet werden. Mit Hilfe des Trigger-Konzeptes (siehe Abschnitt 2.1.1.6) von Chimera ist es möglich, benutzerdefinierte Aktionen mit der Verletzung einer Integritätsbedingung zu verknüpfen. Es gibt zwei unterschiedliche Arten von Integritätsbedingungen, die sich nur durch den Zeitpunkt der Überprüfung einer Integritätsbedingung unterscheiden: • "immediate constraints" • "deferred constraints" Um die genaue Bedeutung der beiden Arten zu verstehen, sind einige Informationen aus Kapitel 2.3 nötig. Anfragen und Datenmanipulationen werden in sogenannten Transaktionen zusammengefaßt. Eine Transaktion besteht aus mehreren Transaktionszeilen und wird durch den "commit"-Befehl beendet. "Immediate constraints" werden nach jeder einzelnen Transaktionszeile überprüft. Im folgenden Beispiel wird also nach jeder Datenmanipulation, sei es nun das Einfügen, Löschen oder Verändern eines oder mehrerer Datensätze geprüft, ob jeder Kunde eine Kontonummer besitzt: define object class kunde attributes name : string, konto_nr: integer constraint immediate hat_keine_kontonummer end; define object class konto attributes konto_nr: integer, guthaben: real key (konto_nr) end; "Deferred constraints" werden am Ende einer Transaktion, also nach erst nach dem Befehl "commit" überprüft. Dieses Vorgehen hat den Vorteil, daß mehrere Aktionen ausgeführt werden können, bevor eine Überprüfung der Integritätsbedingung am Ende einer Transaktion geschieht. Dieses Vorgehen wird durch folgendes Beispiel motiviert; die Problemstellung ist identisch zur obigen, bis auf die Forderung, daß jedes Konto einen Kontoinhaber besitzen muß. Dadurch werden die veränderten Integritätsbedingungen erforderlich: define object class kunde attributes name : string, konto_nr: integer constraints deferred hat_keine_kontonummer end; 13 Inhaltsverzeichnis define object class konto attributes konto_nr: integer, inhaber: string, guthaben: real constraints deferred hat_keinen_inhaber key (konto_nr) end; Falls beide Integritätsbedingungen sofort nach Einfügen eines Datensatzes überprüft würden, könnte kein Datensatz für einen neuen Kunden oder ein neues Konto angelegt werden. Erst durch Überprüfung der beiden Integritätsbedingungen am Ende einer Transaktion ist es möglich, sowohl einen neuen Kunden in die Datenbank einzufügen, als auch ein neues Konto zu eröffnen. Die bisher vorgestellten Integritätsbedingungen nennt man auch "targeted constraints". Dieser Name beruht auf der Tatsache, daß jede Integritätsbedingung eindeutig einer Objektklasse zugeordnet werden kann. Im Gegensatz dazu werden "untargeted constraints" einer ganzen Datenbank zugeordnet. Auch bei diesen freien Integritätsbedingungen gibt es die Unterscheidung zwischen solchen, die sofort überprüft werden, und solchen, die erst am Ende einer Transaktion ausgewertet werden. Die Art und Weise wie eine Integritätsbedingung definiert werden kann wird in Abschnitt 2.2 erläutert. Integritätsbedingungen können auch ohne die Angabe des Bearbeitungsmodus definiert werden. Diese Integritätsbedingungen werden dann automatisch als "deferred constraints" umgesetzt. Bei der Auswertung von Integritätsbedingungen und Trigger ist eine feste Reihenfolge vorgesehen: Zuerst werden alle Trigger ausgewertet und deren Aktionen ausgeführt. Anschließend werden alle Integritätsbedingungen überprüft. 2.1.1.6 Trigger Ein Trigger reagiert auf Veränderungen des Datenbestandes oder auf Aufrufe von Operationen. Im Gegensatz zu Integritätsbedingungen kann der Entwickler allerdings zusätzlich zur Ursache die Folgen frei definieren. Trigger bestehen immer aus drei Teilen: • Event • Condition • Action Ein Trigger feuert bei einem bestimmten Ereignis (engl. event), wertet eine Bedingung (engl. condition) aus und führt im Anschluß eine Aktion (engl. action) aus. Dieses dreistufige Konzept wird in der Datenbanktheorie als ECA-Paradigma bezeichnet. 14 Inhaltsverzeichnis Um einen Chimera-Trigger definieren zu können benötigt der Entwickler Wissen über deklarative Ausdrücke in Chimera (siehe Abschnitt 2.2). Ähnlich wie bei Integritätsbedingungen unterscheidet man auch bei Triggern zwischen "immediate" und "deferred" Triggern. Wie bei Integritätsbedingungen, wird bei Triggern dadurch der Zeitpunkt der Auswertung der Bedingung und die Ausführung der Aktion beeinträchtigt. 2.1.2 Klassenhierarchien und Vererbung in Chimera Eines der Hauptkonzepte der Objektorientierung ist die Vererbung. Vererbung findet immer in einer festgelegten Richtung statt: Eine Oberklasse, vererbt prinzipiell alle extensionalen und abgeleiteten Attribute, Integritätsbedingungen, Trigger und Operationen an alle Unterklassen. Dies bedeutet, daß alle Instanzen einer Unterklasse alle Attribute der Oberklassen besitzt und alle Integritätsbedingungen ihrer Oberklassen erfüllen muß. Zusätzlich stehen alle Operationen der Oberklassen und alle Trigger der Oberklassen zur Verfügung. Ein Trigger reagiert auf alle Änderungen innerhalb der Klassenhierarchie, die durch die den Trigger definierende Objektklasse, als Oberklasse definiert wird. Jede Unterklasse kann zusätzliche Integritätsbedingungen, Trigger und Operationen definieren. Die Definitionsregeln von abgeleiteten Attributen können für eine Unterklasse neu definiert werden. Hinter dem objektorientierten Konzept der Vererbung steht folgende Idee: "Besitzen mehrere Datentypen (Objektklassen) gemeinsame Eigenschaften, so faßt man die Gemeinsamkeiten in einer Klasse zusammen. Die für jeden Datentyp (Objektklasse) spezifischen Eigenschaften definiert man jeweils in einer eigenen Klasse, die man zur Unterklasse der Klasse der Gemeinsamkeiten macht. Alle Deklarationen der Oberklasse vererben sich dann an die Unterklassen" [Inf93]. Das folgende Beispiel definiert in Verbindung mit dem Beispiel aus Abschnitt 2.1.1.3 eine kleine Klassenhierarchie: define object class schueler superclasses person attributes schule: string notnull, klasse: integer notnull, faecher: list-of(string) end; Ein "schueler" ist eine "person", der zusätzliche Merkmale besitzt: Jeder Schüler muß Schüler einer Schule sein und besucht eine bestimmte Klasse. Zusätzlich besucht ein "schueler" den Unterricht in einer Reihe von Fächern. Die Objektklasse "schueler" erbt die Attribute "name", "vorname", "geschlecht" und "adresse" aus der Klasse "person". Dies bedeutet, daß z.B. bei Anfrage an den Namen und Vornamen von einer "person" ebenfalls die Objekte der Klasse "schueler" ausgewertet werden müssen. Abbildung 2.1 erweitertet die obigen Klassenhierarchie um zwei extensionale Objektklassen und eine abgeleitete Objektklasse. 15 Inhaltsverzeichnis Eine Anmerkung zur grafischen Notation im folgenden Beispiel: Es gibt verschiedene grafische Notationen um objektorientierte Klassenhierarchien darzustellen. Folgende Abbildung basiert auf der Darstellung der Bonner Implementation von Chimera ("Chimera Prototyping Tool (CPT)", siehe Kapitel 3): • Vererbungspfeile verweisen immer von der Unterklasse auf die Oberklasse. • Extensionale Objektklassen werden durch einen durchgezogen Rahmen und abgeleitete Objektklassen durch einen gestrichelten Rahmen repräsentiert. person schueler oberstufe student abitur Abbildung 2.1: Klassenhierarchie mit abgeleitete Objektklasse Durch die Verwendung von abgeleiteten Objektklassen wird die Definition von Unterklassen in einer Chimera-Klassenhierarchie eingeschränkt: Abgeleitete Objektklassen dürfen nur abgeleitete Unterklassen besitzen. Diese Einschränkung basiert auf folgendem Problem: Die Objekte extensionaler Unterklassen einer abgeleiteten Oberklasse müssen weiterhin die Bedingungen der Populationsregeln der abgeleiteten Objektklasse erfüllen. Diese Forderung kann zwar durch die Definition einer entsprechenden Integritätsbedingungen umgangen werden, dieses Vorgehen ist allerdings nicht in jedem Fall möglich. Für obiges Beispiel bedeutet dies, daß die abgeleitete Objektklasse "abitur" nur abgeleitete Unterklassen besitzen darf. Klassenhierarchien müssen, wie im obigen Beispiel, eine eindeutige Oberklasse besitzen. Es ist allerdings auf jeder Unterebene einer Klassenhierarchie möglich, Mehrfachvererbungen durchzuführen. Dies bedeutet, daß eine Unterklasse, ob nun extensional oder abgeleitet, die Attribute, Integritätsbedingungen, Trigger und Operationen von zwei oder mehr Oberklassen erbt. Bei Mehrfachvererbungen ist allerdings zu beachten, daß die vererbenden Oberklassen keine zusätzlichen Attribute definieren dürfen, da ansonsten die Ausprägung eines Objektes für jede direkte Oberklasse verschieden sein könnte. 16 Inhaltsverzeichnis 2.2 Deklarative Ausdrücke von Chimera Im vorhergehenden Kapitel wurden die Konzepte eines Chimera-Schemas erläutert. Bei der Behandlung der Schemakonzepte wurde häufig auf die deklarativen Ausdrücke von Chimera verwiesen. Dieser Abschnitt wird nun die Möglichkeiten deklarativer Ausdrücke erläutern. Die Beispiele, die in diesem Abschnitt vorgestellt werden, basieren auf der obigen Klassenhierarchie mit abgeleiteten Objektklassen (siehe Abbildung 2.1). Deklarative Ausdrücke werden mit Hilfe von Termen und Formeln definiert: In deklarativen Ausdrücken repräsentieren Terme Objekte oder einzelne Werte. Terme können atomar oder komplex sein. Atomare Terme bestehen aus Variablen und Konstanten, komplexe Terme aus Listen, Mengen und Tupeln. Formeln bestehen aus Operatoren und Parametern. Man unterscheidet ebenfalls zwischen atomaren und komplexen Formeln. Komplexe Formeln bestehen aus mehreren atomaren Formeln, die mit Hilfe von Konjunktion und Negation kombiniert werden. Ein deklarativer Ausdruck kann aus mehreren Termen und Formeln bestehen. Die einzelnen Bestandteile eines Ausdrucks können mittels Konjunktion zu einem Ausdruck kombiniert werden. Die Konjunktion wird durch ein Komma (",") dargestellt. Um einen deklarativen Ausdruck in Chimera zu definieren, stehen folgende Konzepte zur Verfügung: • Klassenformeln • arithmetische Funktionen • Vergleichsformeln • Aggregatsfunktionen • Mitgliedsformeln • Listenfunktionen • Mengenfunktionen Die obigen Konzepte benötigen Konstanten und Variablen um korrekt angewendet zu werden. Konstanten und Variablen müssen folgende Regeln einhalten: • Zeichenketten müssen in doppelten Anführungszeichen (") stehen. • Variablennamen müssen mit einem großgeschriebenen Buchstaben beginnen und dürfen keine Sonderzeichen (z.B. "ä", "ö", "ü" und "ß") enthalten. Durch eine Klassenformel (engl. class formula) wird der Typ einer Variable festgelegt. Als Typ einer Variable können Wertetypen, Werteklassen und Objektklassen verwendet werden. Die Bedeutung der Variable unterscheidet sich zwischen Wertetypen und -klassen sowie Objektklassen. Wird eine Variable an eine Wertetyp oder eine Werteklasse gebunden, so repräsentiert sie einen Wert des jeweiligen Typs oder der jeweiligen Klasse. Im Falle einer Zuordnung zu einer Objektklasse, repräsentiert die Variable die Objektidentifikatoren der einzelnen Objekte: person(X) integer(I) geschlecht(G) Durch obige Klassenformeln wird die Variable X an die Objektklasse "person" gebunden. Über die Variable X sind nun also alle Objekte der Klassen "person" ansprechbar. Die Va17 Inhaltsverzeichnis riable I hingegen repräsentiert eine ganze Zahl. Der Wertebereich der Variable G ist auf die Werte der Werteklasse "geschlecht" eingeschränkt. Auf die Attribute einer Objektklasse kann mit dem Punkt-Operator (".") zugegriffen werden. Die Attributfunktion selektiert das entsprechende Attribut der Objektklasse: X.name X.vorname Z.klasse Ein wichtiges Konzept deklarativer Ausdrücke sind Vergleichsformeln. Zur Definition von Vergleichsformeln innerhalb deklarativer Ausdrücke können folgende Operatoren verwendet werden: • = • \= • < • <= • > • >= Mit Hilfe dieser Vergleichsoperatoren lassen sich folgende Vergleichsformeln bilden: X.name = "Horn" X.name != Z.name Z.klasse <= 9 Z.adresse.wohnort = "Meckenheim" Das letzte Beispiel zeigt einen Pfadausdruck. Pfadausdrücke erlauben einen gezielten Zugriff auf einzelne Komponenten eines strukturierten Attributes. Basierend auf einer Schemadefinition unterstützt Chimera beliebige lange Pfadausdrücke in deklarativen Ausdrücken. Die Pfadausdrücke können sowohl auf der linken als auch auf der rechten Seite von Operatoren stehen. Die obigen Beispiele für Vergleichsformeln sind nicht vollständig, da die Variablen X und Z sind nicht an eine Objektklasse gebunden wurden. Daher können obige Beispiele nicht korrekt ausgewertet werden. Jede Variable, die innerhalb eines deklarativen Ausdrucks verwendet wird, muß mittels einer Klassenformel an einen Wertetyp, eine Werteklasse oder eine Objektklasse gebunden werden. Durch die Konjunktion von Klassen- und Vergleichsformeln entstehen vollständige deklarative Ausdrücke: person(X), X.name = "Horn" person(X), student(Z), X.name != Z.name Ein weiteres Konzept zur Definition deklarativer Ausdrücke sind Mitgliedsformeln (engl. membership formula). Nachdem eine Variable durch eine Klassenformel einem Wertebereich zugeordnet wurde, kann mit Hilfe einer Mitgliedsformel der Wertebereich der Variable zusätzlich eingeschränkt werden. Mitgliedsformeln können für die Zugehörigkeit zu Objektklassen, Wertetypen und Werteklassen definiert werden: person(X), X in abitur Durch obigen deklarativen Ausdruck wird die Variable X an alle Objektidentifikatoren der Objektklasse "person" gebunden, die gleichzeitig Mitglied der abgeleiteten Objektklasse "abitur" sind. 18 Inhaltsverzeichnis Das letzte Konzept zur Definition deklarativer Ausdrücke sind Funktionen und Operatoren, die dazu dienen Terme zu definieren, die Werte, Listen und Mengen bearbeiten. Zur Definition deklarative Ausdrücke in Chimera können folgende Funktionen und Operatoren verwendet werden: Arithmetische Fkt. Aggregatfunktionen Listenoperatoren Mengenoperatoren Addition: + Maximum: max Konkatenation: // Vereinigung: + Subtraktion: - Minimum: min Kopf der Liste: hd Differenz: - Multiplikation: * Summe: sum Rest der Liste: tl Aufspalten: * Division: / Durchschnitt: avg Modulo: mod Kardinalität: card Zuweisung: = 2.2.1 Anwendung deklarativer Ausdrücke Im letzten Abschnitt wurden die Möglichkeiten und Konzepte deklarativer Ausdrücke vorgestellt. Die folgende Abschnitte befassen sich mit der Anwendung deklarativer Ausdrücke. Deklarative Ausdrücke werden zur Formulierung von Anfragen benötigt (siehe Kapitel 2.3) und zur Definition der Ausprägung von Schemakomponenten angewendet werden. Deklarative Ausdrücke müssen zur Definition folgender Konzepte verwendet werden: • Klassenpopulationsregeln • Attributdefinitionsregeln • Definition von Triggern • Definition von Integritätsbedingungen Die Ausprägung von Schemaobjekten wird in der Implementation des Objektes definiert. Die Ausprägungen können mittels verschiedener Schlüsselworte zu einer Implementation einer Objektklasse zusammengefaßt werden. Alle Konzepte, die im Implementationsteil einer Objektklassendefinition definiert werden, können durch mehrere Regeln definiert wenden. Daten von abgeleiteten Objektklassen müssen via Populationsregeln definiert werden. Bei der Definition einer solchen Regel dürfen nur Informationen von Oberklassen der zu definierenden Klasse verwendet werden. Populationsregeln einer abgeleiteten Klasse werden nach dem Schlüsselwort "population" definiert: 19 Inhaltsverzeichnis define object class oberstufe superclasses schueler attributes note_leistungskurs1: note_leistungskurs2: note_grundkurs1: note_grundkurs2: durchschnitt: constraints illegale_note end; define object class abitur derived superclass oberstufe attributes durchschnitt: trigger abitur_bestanden end; integer, integer, integer, integer, integer derived integer redefined define implementation for abitur population abitur(X) <oberstufe(X), X.klasse = 13, X.durchschnitt <= 4 end; Obige Populationsregel definiert die Ausprägung der abgeleiteten Klasse "abitur". Alle Schüler der dreizehnten Klasse mit einem Notendurchschnitt von 4 oder besser gehören zur Population der Klasse. Die Definition der Populationsregel der Klasse "abitur" basiert auf dem abgeleiteten Attribut "durchschnitt" der Objektklasse "oberstufe". Attributdefinitionsregeln für abgeleitete Attribute werden innerhalb der Implementation einer Objektklasse nach dem Schlüsselwort "attributes" definiert. Folgende Definition berechnet den Notendurchschnitt eines Schülers der Oberstufe: define implementation for oberstufe attributes Self.durchschnitt <avg( Self.note_leistungskurs1, Self.note_leistungskurs2, Self.note_grundkurs1, Self.note_grundkurs2 ) end; Obige Attributdefinitionsregel definiert die Berechnung des Attributes "durchschnitt" der Objektklasse "oberstufe". Das Beispiel benutzt eine in der Regel nicht eingeführt Variable "Self". Bei der Definition von Attributdefinitionsregeln kann die vom System 20 Inhaltsverzeichnis vordefinierte Variable "Self" verwendet werden um Objekte der aktuellen Klasse direkt anzusprechen. In der Definition der abgeleiteten Klasse "abitur" wird das Attribut "durchschnitt" erneut definiert. Dies bedeutet, daß die Berechnungsregel der Objektklasse "oberstufe" nicht für Objekte der Klasse "abitur" gelten soll. Der Durchschnitt eines Abiturienten soll auf einer anderen Berechnungsregel basieren als der eines Oberstufenschülers: redefine implementation for abitur attributes Self.durchschnitt <avg( Self.note_leistungskurs1, Self.note_leistungskurs1, Self.note_leistungskurs2, Self.note_leistungskurs2, Self.note_grundkurs1, Self.note_grundkurs2 ) end; Die obige Redefinition der Berechnungsregel für die abgeleitete Objektklasse "abitur" hat keinen Einfluß auf die Populationsregel der Objektklasse. Durch Redefinition können Attributdefinitionsregeln und die Definitionen von Integritätsbedingungen und Triggern verändert werden. Ab einer Redefinition wird jeweils die redefinierte Regel oder Definition an alle Unterklassen vererbt. Integritätsbedingungen werden im Implementationsteil einer Objektklasse formuliert. Die Signatur einer Integritätsbedingung wird in der Definition der dazugehörigen Objektklasse festgelegt. Die obige Definition der Objektklasse "oberstufe" definiert die Integritätsbedingung "illegale_note". Die Objekte, die die Integritätsbedingung verletzen, werden durch folgende deduktive Regel hergeleitet: define implementation for oberstufe constraints illegale_note(Self) <Self.note_leistungskurs1 < Self.note_leistungskurs1 > illegale_note(Self) <Self.note_leistungskurs2 < Self.note_leistungskurs2 > illegale_note(Self) <Self.note_grundkurs1 < 0, Self.note_grundkurs1 > 6 illegale_note(Self) <Self.note_grundkurs2 < 0, Self.note_grundkurs2 > 6 0, 6 0, 6 end; Obige Integritätsbedingung wird verletzt, sobald für einen Schüler der Oberstufe eine illegale Note für einen der vier Kurse eingegeben wird. Sobald eine Note schlechter als 6 und besser 21 Inhaltsverzeichnis als 1 eingegeben wird, verletzt die Modifikation des Objektes die Integritätsbedingung. Der Wert 0 für Noten wird zusätzlich noch zugelassen, um einen Wert für Noten eingeben zu können, die noch nicht vergeben wurden. Obige Bedingung ist ein Beispiel dafür, daß Integritätsbedingungen durch mehrere Regeln definiert werden können. Entscheidend für die Verletzung einer Integritätsbedingungen ist hierbei, daß mindesten eine der Regeln verletzt wird. Die Definition eines Triggers ist der letzte Verwendungszweck von deklarativen Ausdrücken bei der Definition eines Chimera-Schemas. Die Definition eines Triggers besteht aus drei Abschnitten: • Ereignis: Ein Trigger ist in der Lage auf mehrere Ereignisse innerhalb der Population einer Objektklasse zu reagieren. Die einzelnen Elemente der Liste von Ereignissen werden durch ein Semikolon (";") voneinander getrennt. • Bedingung: Zur Definition des Bedingungsteils eines Triggers können beliebige deklarative Ausdrücke verwendet werden. • Aktion: Aktionen bestehen aus DML-Operationen von Chimera Folgendes Beispiel definiert den Trigger "abitur_bestanden" der Objektklasse "abitur": define trigger abitur_bestanden for abitur events modify(durchschnitt) condition Self.durchschnitt <= 4, Self.note_leistungskurs1 \= 0, Self.note_leistungskurs2 \= 0, Self.note_grundkurs1 \= 0, Self.note_grundkurs2 \= 0 action generalize(abitur, schueler, Self) Obiger Trigger verallgemeinert ein Objekt der Objektklasse "abitur", sobald der berechnete Notendurchschnitt besser als 4 ist und alle Noten eingeben wurden. Das Objekt wird daraufhin in die Oberklasse "schueler" verschoben. Die zusätzlichen Informationen eines Objektes der Klasse "oberstufe" gehen in diesem Beispiel allerdings durch die Verallgemeinerung verloren. 2.3 Imperative Ausdrücke von Chimera Vor der Vorstellung der imperativen Ausdrücke von Chimera, muß noch das Transaktionskonzept von Chimera erläutert werden: Anfragen und Datenmanipulationen werden in Transaktionen zusammengefaßt. Eine Transaktion wird mit dem Befehl "commit" oder "rollback" beendet. Der "commit"-Befehl schreibt alle Änderungen der Transaktion endgültig in die Datenbank. "rollback" macht alle Änderungen der Transaktion rückgängig und beläßt die Datenbank in dem Zustand, der vor Beginn der Transaktion existierte. Am Ende einer Transaktion werden alle "deferred"-Trigger und -Integritätsbedingungen ausgewertet. Chimera benötigt keinen expliziten Befehl, um eine Transaktion zu beginnen. Der 22 Inhaltsverzeichnis erste imperative Ausdruck nach einem "commit" oder "rollback" startet eine neue Transaktion. Eine Transaktion kann aus einer oder mehreren Transaktionszeilen bestehen. Eine Transaktionszeile wird durch ein Semikolon (";") abgeschlossen. Alle Variablenbindungen gelten immer nur in einer Transaktionszeile. In einer Transaktionszeile können mehrere Befehle durch den Sequenzoperator Komma (",") oder durch den Pipeoperator ("|") zusammengefaßt werden. Die Unterschiede zwischen den beiden Operatoren besteht in der Abarbeitungsreihenfolge der einzelnen Befehle: In einer Sequenz wird jeder Befehl komplett ausgeführt, bevor der nächste Befehl abgearbeitet wird. Durch diese Abarbeitung der Befehle können Mengen von Variablenbindungen entstehen, die dann von nächsten Befehl komplett bearbeitet werden müssen. Durch den Pipeoperator wird ein Befehl immer einmal abgearbeitet, danach eine eventuelle Bindung einer Variable an den nächsten Befehl weitergeben, dieser abgearbeitet und danach erst der erste Befehl wieder ausgeführt. Anfragen können in Chimera mit Hilfe zweier unterschiedlicher Operationen gestellt werden: select und display Der Unterschied zwischen beiden Operationen ist der Umgang mit dem Ergebnis der Anfrage: "display" zeigt das Ergebnis auf dem Bildschirm an, "select" bindet Objektidentifikatoren an eine Variable. Die allgemeine Syntax von "select"- und "display"Befehlen lautet select(V where B) display(A where B) wobei V eine Liste von Objektvariablen, A eine Liste von Attributen, und B die selektierende Bedingung ist, die alle in V bzw. A auftretenden Variablen an jeweils eine Objektklasse bindet und die Auswahl zusätzlich beliebig einschränkt. Die Bedingung kann ein beliebiger deklarativer Ausdruck sein: select(X, Y where person(X), adresse(Y) X.adresse = Y) display(Z.name, Z.adresse.wohnort where schueler(Z), Z in oberstufe, Z.klasse = 12) Die Bindungen der Variablen X und Y im obigen "select"-Beispiel können in einer Transaktionszeile zur Datenmanipulationen eingesetzt werden. Die selektierten Attribute des "display"-Befehls werden auf dem Bildschirm ausgegeben und können nicht weiterverwendet werden. Imperative Ausdrücke von Chimera können zusätzlich zu den obigen Anfrageoperationen durch fünf Datenmanipulations- und Objektmigrationsoperationen formuliert werden. Mit Hilfe der Operationen können Objekte erzeugt, gelöscht oder die Ausprägung von Objekten verändert werden. Folgende Operationen stehen zur Verfügung: 23 Inhaltsverzeichnis Objektmigration Datenmanipulation • generalize • create • specialize • delete • modify Die beiden Objektmigrationsoperationen verändern die Klasse, zu der ein Objekt gehört. Mittels der "generalize"-Operation kann ein Objekt von einer Unterklasse in eine Oberklasse migrieren. Durch diesen Operation verliert das Objekt zusätzliche, in der Unterklasse definierte, Attribute. Die Operation benötigt drei Parameter, um die Aktion ausführen zu können: den Namen der Unterklasse, den Namen der Oberklasse und die Objektidentifikatoren der Objekte: select(Z, where student(Z), Z.semester > 20), generalize(student, person, Z); Obiges Beispiel selektiert zuerst alle Studenten, die länger als 20 Semester studieren und exmatrikuliert sie anschließend indem die Objekte in die Objektklasse "person" verschoben werden. Die selektierten Objekte der Klasse "student" sind nach dieser Operation nur noch Objekte der Klasse "person". Die Objekte der Klasse "student" verlieren durch diese Operation alle Attribute, die in den Klassen "schueler" und "student" definiert wurden. "specialize" verschiebt ein Objekt von einer Oberklasse in eine Unterklasse. Das verschobene Objekt erhält dadurch die in der Unterklasse definierten neuen Attribute. Die "specialize"-Operation benötigt dafür vier Parameter: den Namen der Oberklasse, den Namen der Unterklasse, die Objektidentifikatoren und die Werte der zusätzlichen Attribute: select(X where person(X), X.name = "Horn"), specialize(person, schueler, X, [schule: "Konrad-AdenauerGymnasium", klasse: 10, faecher: <"Deutsch">]); Obiges Beispiel selektiert alle Objekte der Klasse "person", deren Attribut Name den Wert "Horn" hat und verschiebt sie in die Unterklasse "schueler". Die Werte der in der Unterklasse "schueler" definierten Attribute werden in Form eines Tupels definiert. Der Unterschied zwischen den beiden Objektmigrationsoperationen und einer Kombination aus den noch vorzustellenden "create"- und "delete"-Operationen liegt in dem Wert des Objektidentifikators: Durch die Migration wird die OID eines Objektes nicht verändert. Ein Löschen und erneutes Einfügen eines neuen Objektes mit identischen Werten hingegen, verändert den Wert des Objektidentifikators. Im objektorientierten Kontext sind die beiden Objekte dadurch nicht identisch. Die drei Datenmanipulationsoperationen erzeugen oder löschen Objekte bzw. manipulieren die Werte der jeweiligen Attribute. Die "create"-Operation benötigt folgende drei Parameter: 24 Inhaltsverzeichnis • den Namen der Objektklasse, in die ein neues Objekt eingefügt werden soll • die Werte aller Attribute des zu erzeugenden Objektes • eine Variable für den erzeugten Objektidentifikator Das folgendes Beispiel zeigt die Kombination zweier "create"-Befehle in einer Transaktionszeile: create(adresse, (strasse: "Lueftelberger Str. 9", plz: 53340, wohnort: "Meckenheim"), A), create(person, (name: "Horn", vorname: "Michael", geschlecht: "maennlich", adresse: A), P); Der erste "create"-Befehl im obigen Beispiel gibt als Ergebnis seiner Aktion die OID des erzeugten Objektes zurück. In einer Transaktionszeile kann diese OID beliebig weiterverwendet werden. Im Beispiel bedeutet dies, daß nach der Erzeugung einer neuen "adresse", der Wert des Objektidentifikators im zweiten "create"-Befehl als Wert des Attributes "adresse" eingesetzt wird. Der Wert der Variable A ist allerdings für den Rest der Transaktionszeile nicht veränderbar! Die "modify"-Operation ändert den Wert eines Attributes. Die Operation benötigt drei Parameter: den Klassenname mit dem dazugehörigen Attribut, die Objektidentifikatoren und die neuen Werte: select(X where student X ), modify(student.semester, X, X.semester+1); Im obigen Beispiel wird der Wert des Attributes "semester" von allen Objekten der Klasse "student" um eins erhöht. Die durch den "select"-Befehl gebundene Variable X wird zur Selektion der betroffenen Objekte verwendet. Die letzte Operation zur Datenmanipulation löscht ein vorhandenes Objekt aus einer Objektklasse. Die "delete"-Operation benötigt für das Löschen von Objekten den Namen der entsprechenden Objektklasse und die entsprechenden Objektidentifikatoren: select(X where student(X), X.name = "Horn"), delete(student, X); Obiges Beispiel löscht alle Objekte der Klasse "student", deren Namensattribut den Wert "Horn" hat. Aufgrund von Vererbung innerhalb von Klassenhierarchien ist die Verwendung der "delete"-Operation mit Bedacht einzusetzen: Die Operation löscht das Objekt in allen Klassen der Hierarchie. Nach der Ausführung der obigen Aktion werden auch keine Objekte der Klasse "person" existieren, deren Namensattribut den Wert "Horn" hat. Die "delete"-Operation löscht das komplette Objekt, ohne Rücksicht auf den Menge der Klassen, in denen es enthalten ist. In den meisten Fällen wird die "generalize"-Operation eher den gewünschten Effekt erzielen, da dadurch diese Operation das Objekt nur aus der Klasse "student" und allen Unterklassen entfernt wird. 25 Inhaltsverzeichnis Michael Horn 3 Das Chimera Prototyping Tool Das Chimera Prototyping Tool (CPT) ist eine Implementierung von Chimera an der Bonner Universität (http://www.informatik.uni-bonn.de/~idea). Die Bonner Umsetzung von Chimera basiert auf dem in Prolog realisierten relationalen Datenbankmanagementsystem Phoenix. Das Phoenix-System ist in ECLiPSe-Prolog realisierte Implementierung der aktive und deduktive Datenbankprogrammiersprache (engl. database programming language DBPL) Phoenix, die auf dem relationalen Datenmodell basiert. Die Daten werden dabei entweder im Hauptspeicher des Computers gehalten oder persistent auf einem Datenträger gespeichert. Bei der persistenten Speicherung wird auf das MegaLog-Untersystem von ECLiPSe zurückgegriffen. Die graphische Benutzeroberfläche des CPT (CPT/GUI) unterstützt den Benutzer bei dem Entwurf von Chimera-Datenbanken. Die CPT/GUI bietet einen Überblick über die Klassenhierarchien eines Chimera-Schemas und die einzelnen Abhängigkeiten zwischen den Objektklassen. Alle Informationen bzgl. einer Objektklasse eines Schemas können mit Hilfe der graphischen Oberfläche visualisiert werden. Abbildung 3.1 zeigt den Dialog zum Entwurf und zur Modifikation einer Objektklasse. Der Dialog zur Definition von Objektklassen verteilt die unterschiedlichen Optionen einer Objektklasse auf mehrere Karteikarten. Die auf der nächsten Seite abgebildete Karteikarte dient zur Definition von Attributen. Auf den folgenden Seiten können Integritätsbedingungen, Operationen, Trigger und Populationsregeln definiert und modifiziert werden. Eine genauere Beschreibung der Funktionen und Möglichkeiten des Chimera Prototyping Tools befindet sich im CPT-Handbuch ([GLM96]). 26 Inhaltsverzeichnis Abbildung 3.1: Graphischer Entwurf einer Objektklasse mit Hilfe der graphischen Benutzeroberfläche des Chimera Prototyping Tools (CPT/GUI) Die folgenden Abschnitte beschäftigen sich mit der Architektur der Bonner Implementierung, dem Bonner Chimera-Dialekt und den Unterschieden zwischen Chimera und dem Bonner Chimera-Dialekt. Der letzte Abschnitt dieses Kapitels beschäftigt sich mit der Abbildung des objektorientierten Datenmodells Chimera auf das relationale Datenmodell von Phoenix. 3.1 Architektur des CPT Das Chimera Prototyping Tool besteht aus zwei Benutzerschnittstellen, einem ChimeraCompiler, einem Phoenix-Interpreter und dem ECLiPSe-Prolog-System. Bei der Arbeit mit dem CPT hat der Benutzer die Wahl zwischen einer Kommandoschnittstelle (CPT/CI) und einer auf Tcl/Tk basierenden grafischen Oberfläche (CPT/GUI). 27 Inhaltsverzeichnis DDL DML CPT/GUI SEA PRPT CPT/CI PRDT CARDT PROP Chimera-Compiler Phoenix-DBPL-Interpreter CDD ECLiPSe CPT MegaLog-DB Prolog-DB (persistent) (temporär) Abbildung 3.2: Architektur des Chimera Prototyping Tools (CPT) inklusive der zusätzlichen Entwicklungswerkzeuge und -assistenten 28 Inhaltsverzeichnis Im Rahmen mehrere Diplom- und Forschungsarbeiten sind im Umfeld des CPT weitere Entwicklungswerkzeuge und -Assistenten entwickelt worden: • Schema Evolution Assistant (SEA, [Lem94 und LM95]) • Passive Rule Prototyping Tool (PRPT, [Schu99]) • Passive Rule Design Tool (PRDT, [Asc96, LM97]) • Chimera Active Rule Design Tool (CARDT, [Schi98]) • Propagation Rule Compiler (PROP, [DG94]) Alle Erweiterungen basieren auf dem CPT/GUI. Die Architektur des CPT ist streng hierarchisch geordnet: Alle Datendefinitions- und Datenmanipulationsbefehle werden von den beiden Benutzerschnittstellen an den Chimera-Compiler weitergereicht. Während der Erstellung oder des Einlesens eines Chimera-Schemas werden die Schemainformationen durch einen Parser in eine interne Darstellung des Chimera Schemas überführt. Die interne Schemadarstellung wird im Chimera Data Dictionary (CDD) gespeichert. Das genaue Aussehen des CDD wird in Abschnitt 3.3 erläutert. Basierend auf der internen Repräsentation des Chimera-Schemas übersetzt der Chimera-Compiler Datendefinitions- und Datenmanipulationsbefehle. Nach der Übersetzung der Chimera-Befehle in entsprechende Phoenix-Befehle durch den Compiler, werden die Befehle vom Phoenix-DBPL-Interpreter verarbeitet und an das ECLiPSe–System weitergereicht. Je nach gewähltem Modus werden die Daten entweder temporär im Arbeitsspeicher (Prolog-Modus) oder persistent auf einem Datenträger (MegaLogModus) gespeichert. Alle Konfigurationsinformationen werden in einer Datei (".chimerarc") gespeichert. In dieser Datei muß das CPT-Verzeichnis, ein Datenverzeichnis und der oben beschriebene Datenbankmodus konfiguriert werden. Chimera erwartet die Konfigurationsdatei im HomeVerzeichnis des jeweiligen Benutzers. 3.2 Der Bonner Chimera-Dialekt Während der Implementation des CPT, sind einige Einschränkungen und Veränderungen an der Chimera-Sprachdefinition vorgenommen worden. Diese Veränderungen wurden durch die gewählte Implementationsweise motiviert. Die folgenden Abschnitte basieren auf der Diplomarbeit von Stefan Schubert ([Sch99]), der Implementationsdokumentation des CPT von Ulrike Griefahn und Thomas Lemke ([GL96]) und eigenen Beobachtungen durch den Umgang mit dem CPT. 29 Inhaltsverzeichnis 3.2.1 Unterschiede zwischen Chimera- und CPT-Datenmodell Basierend auf der im folgenden Abschnitt vorgestellte relationalen Übersetzung für ChimeraObjektklassen und Klassenhierarchien, existieren einige Einschränkungen für abgeleitete Objektklassen: • Abgeleitete Objektklassen dürfen keine neuen extensionalen Attribute definieren. • Abgeleitete Objektklassen dürfen nur genau eine direkte Superklasse besitzen. • Abgeleitete Objektklassen dürfen nur abgeleitete Unterklassen besitzen. Die Forderung, daß abgeleitete Objektklassen keine extensionalen Attribute besitzen dürfen, wird durch die Tatsache motiviert, daß eine abgeleitete Objektklasse mit extensionalen Attributen materialisiert werden müßte, um die extensionalen Attribute abspeichern zu können. Die Forderung nach einer eindeutigen direkten Oberklasse basiert auf dem Problem der Ausprägung eines Objektes einer abgeleiteten Klasse bei Mehrfachvererbung. Durch Mehrfachvererbung vererben mehrere Superklassen ihre Attribute, Integritätsbedingungen usw. an die Unterklasse. Durch die Populationsregeln einer abgeleiteten Klasse werden immer ganze Objekte einer Klasse in die Unterklasse übernommen. Je nach Herkunft der Objekte sind nicht alle Attribute des Objektes der Unterklasse nach der Population mit Werten belegt. Um eine komplexe Überprüfung bei Mehrfachvererbung zu umgehen, ist obiges Verbot formuliert worden. Es ist zu beachten, daß das CPT keinen Fehler meldet, falls eine solche Mehrfachvererbung definiert worden ist. Die letzte Einschränkung basiert auf dem Problem, daß die Populationsregeln einer abgeleiteten Klasse in Integritätsbedingungen einer extensionalen Unterklasse übersetzt werden müßten. Dieses Vorgehen ist allerdings nur bei einfachen Populationsregeln möglich. Komplexe Populationsregeln lassen sich nicht ohne beachtlichen Aufwand in entsprechende Integritätsbedingungen übersetzen. Dieses Problem wird durch die aktuelle Implementierung ebenfalls nicht erkannt. Für ein CPT-Schema gelten ansonsten noch folgende Einschränkungen: • Jede Klassenhierarchie muß auf einer eindeutigen Superklasse basieren. • Die Namen von Integritätsbedingungen müssen, bezogen auf das gesamte Schema, eindeutig sein. Chimera fordert nur eine Eindeutigkeit des Namens bezogen auf eine Objektklasse. • Das CPT unterstützt in der momentanen Version noch keine Schlüsselattribute. • Das Schlüsselwort für Listen, Sätze und Tupel wird im CPT anders geschrieben als durch die Chimera-Sprachdefinition vorgegeben (list_of anstelle von list-of usw.). • Bei der Definition von Wertetypen und –Klassen dürfen keine verschachtelten Listen, Sätze oder Tupel definiert werden. 30 Inhaltsverzeichnis 3.2.2 Unterschiede bei deklarativen und imperativen Ausdrücken In der Bonner Chimera-Implementation auch Veränderungen bei deklarativen und imperativen Ausdrücken. Das CPT unterstützt keine "null"-Werte für Attribute, da daß verwendete Phoenix-System diese Werte nicht unterstützt. Dieses Problem beruht auf der Tatsache, daß das ECLiPSe-Prolog-System keine "null"-Werte für die bereitgestellten Datentypen unterstützt. Das Phoenix-System benutzt die Datentypen von ECLiPSe ohne den für Datenbanken erwünschten Wert "null" zusätzlich zu definieren. Der Grund für das Fehlen des Wertes ist der enorme Aufwand, den eine Implementierung von "null"-Werten mit sich bringt: Alle Datentypen müssen redefiniert werden, alle Operationen müssen erweitert werden usw. Das Fehlen von "null"-Werten bedeutet, daß bei jeder Datendefinition alle Attribute eines Objektes mit Werten initialisiert werden müssen. Die "notnull"-Integritätsbedingung, die bei der Definition von Attributen in Chimera verwendet werden kann, wird nicht unterstützt. Des weiteren existieren noch zusätzliche Veränderungen: • Das CPT unterstützt keine benutzerdefinierte Sortierung für die Rückgabewerte von select- und display-Kommandos. • Durch das Löschen von Objekten können sogenannte hängende Referenzen entstehen. Das CPT besitzt keinen Mechanismus um diese referentielle Integrität zu überprüfen. • Trigger können momentan noch nicht auf Anfragen reagieren. • Die Aggregatfunktion von Chimera (card()) wird im CPT durch das Schlüsselwort count() definiert. • Die Klammersymbole für Listen, Sätze und Tupel wurden verändert. Folgende Klammern müssen verwendet werden: set_of Hallo { } list_of Hallo [ ] record_of Hallo ( ) 3.3 Abbildung des objektorientierten Datenmodells nach Phoenix Dieser Abschnitt beschäftigt sich mit der Übersetzung des objektorientierten Datenmodells von Chimera auf das relationale Modell von Phoenix. Mit Hilfe der graphischen Benutzeroberfläche oder der Kommandoschnittstelle kann ein neues Schema definiert oder ein bestehendes Schema aus einer Datei geladen werden. Die erste Syntaxanalyse des Schemas liefert eine interne Darstellung des zu übersetzenden Schemas; diese Darstellung wird in einer Prolog-Datenbank namens Chimera Data Dictionary (CDD) gespeichert. Der Chimera Compiler übersetzt im Anschluß jeden einzelnen Eintrag des CDD in entsprechende Phoenix-Befehle. Die Klassenhierarchie von Kapitel 2 bestehend 31 Inhaltsverzeichnis aus den Objektklassen "adresse", "person", "schueler", "oberstufe" und "abitur" wird durch folgende Einträge im CDD dargestellt: ******************************************** *** module ******************************************** (1,chimera): chimera (2,chimera): user ******************************************** *** object_class ******************************************** (4,user): adresse, [extensional] (8,user): person, [extensional] (13,user): schueler, [extensional] (18,user): oberstufe, [extensional] (25,user): abitur, [derived] ******************************************** *** value_class ******************************************** (3,user): geschlecht, string ******************************************** *** superclass ******************************************** (14,user): person, schueler (19,user): schueler, oberstufe (26,user): oberstufe, abitur ******************************************** *** attribute ******************************************** (5,user): adresse, strasse, string, [extensional] (6,user): adresse, plz, number, [extensional] (7,user): adresse, wohnort, string, [extensional] (9,user): person, name, string, [extensional] (10,user): person, vorname, string, [extensional] (11,user): person, geschlecht, geschlecht, [extensional] (12,user): person, adresse, adresse, [extensional] (15,user): schueler, schule, string, [extensional] (16,user): schueler, klasse, integer, [extensional] (17,user): schueler, faecher, list_of(string),[extensional] (20,user): oberstufe, note_leistungskurs1, integer,[exten.] ... Abgesehen von den obigen CDD-Kategorien existieren noch folgende zusätzlichen Kategorien im CDD, die die jeweilige Definition und die dazugehörigen Regeln der zusätzlichen Schemakonzepte von Chimera repräsentieren: 32 Inhaltsverzeichnis • Value Classes • Attributs- und Klassenpopulationsregeln • Trigger • Integritätsbedingungen • Operationen • Sichten Jeder Eintrag in der CDD-Datenbank besitzt einen Präfix bestehend aus einer fortlaufenden Nummer und dem Namen des Benutzers. Die Prolog-Prädikate "get_cdd/4", "put_cdd/4" und "del_cdd/4" dienen zur Manipulation einzelner CDD-Einträge. "get_cdd/4" ließt Einträge aus dem CDD, "put_cdd/4" schreibt Einträge in das CDD und "del_cdd/4" löscht bestehende Einträge aus dem CDD. Die Parameter aller drei Operationen ist identisch: • ID: Der erste Parameter enthält die ID eines Elementes des CDD. • Modul: Der zweite Parameter enthält das Module, zu dem die Elemente gehören. Dies entspricht in der momentanen Implementation immer dem Module "user". • Konzept Name: Der dritte Parameter identifiziert das Konzept, zu dem die Einträge gehören müssen. • Konzept: Der letzte Parameter liefert eine Liste der eigentlichen Werte der gewünschten Einträge. Jeden der drei obigen Befehle gibt es ebenfalls mit drei oder zwei Parametern. Die dreistellige Version der Prädikate benötigt keine ID und die zweistellige Version benötigt zusätzlich kein Modul. Folgendes Beispiel, basierend auf dem zweistelligen Prädikat "get_cdd/2" liefert folgende Ausgabe: [Chimera] get_cdd(attribute, Werte). Werte = [adresse, strasse, string, [extensional]] More?(;) [Chimera] put_cdd(object_class, [klasse, [extensional]]). [Chimera] put_cdd(attribute, [klasse, attribut, string, [extensional]]). Der erste Befehl des obigen Beispiels liefert alle Attribute, die im CDD eingetragen sind. Das ECLiPSe-System zeigt allerdings immer nur eine Bindung der Variable "Werte" an, der Benutzer muß durch die Eingabe eines Semikolons (";") die Ermittlung eines weiteren Wertes manuell anstoßen. Der Rückgabewert wird in Form einer Liste zurückgegeben. Die Liste enthält den Klassennamen, Namen, Datentyp und den Modus des Attributes. Der Modus 33 Inhaltsverzeichnis eines Attributes ist entweder extensional oder abgeleitet. Die letzten beiden Befehle erzeugen eine neue extensionale Objektklasse mit Namen "klasse" und ein extensionales Attribut "attribut" mit Datentyp "string". Auf den folgenden Seiten wird nun das Vorgehendes CPT bei der Schemaübersetzung von Chimera nach Phoenix aufgezeigt. Jedes der in Kapitel 2 vorgestellten Schemakonzepte wird hierbei in Kombinationen von Konzepten in Phoenix überführt: Objektklassen, Integritätsbedingungen, Sichten und Werteklassen werden durch Relationen und Trigger durch aktive Regeln in Phoenix realisiert. Eine kurze Anmerkung zum Sprachgebrauch in den folgenden Abschnitten dieses Kapitels: Im objektorientierten Datenmodell von Chimera existieren Werteklassen, Wertetypen, abgeleitete und extensionale Objektklassen, Sichten, Integritätsbedingungen und Trigger. Im relationalen Datenmodell von Phoenix existieren dagegen abgeleitete und extensionale Relationen, aktive und passive Regeln. 3.3.1 Werteklassen und -typen Werteklassen werden in Phoenix durch extensionale Relationen dargestellt. Dieses Vorgehen wird durch die endliche Anzahl an zulässigen Werten, die zudem noch explizit mittels add und drop definiert werden müssen, motiviert. Eine Besonderheit stellt allerdings das Aussehen der Phoenixrelationen dar. Die Chimera Werteklasse "geschlecht" define value class geschlecht: string end; wird durch folgende Phoenixrelation realisiert: extensional relation geschlecht ( dummy(integer, 1, +), geschlecht(term, A, -) ) Die "dummy"-Spalte der Relation wird benötigt, da Relationen in Phoenix mindestens ein Nicht-"term"-Attribut besitzen müssen. Diese Einschränkung bzw. Forderung geht auf eine entsprechende Bedingung für Megalog-Relationen zurück. Die atomaren Datentypen von Chimera entsprechen weitgehend den Datentypen von Phoenix. Einzige Ausnahme bildet hierbei der "string"-Datentyp, der in Phoenix durch den Datentyp "atom" repräsentiert wird. 34 Inhaltsverzeichnis 3.3.2 Objektklassen und Klassenhierarchien Bei der Übersetzung eines objektorientierten Chimera-Schemas in ein relationales PhoenixSchema werden folgende zwei Fälle unterschieden: • extensionale Chimera-Objektklassen inklusive ihrer extensionalen Attribute • abgeleitete Attribute extensionaler Objektklassen und abgeleitete Objektklassen Extensionale Objektklassen inklusive ihrer extensionalen Attribute werden durch eine Kombination aus extensionaler und abgeleiteter Relation realisiert: define object class person attributes name: string( 30 ), vorname: string( 30 ) end; Obige Objektklasse wird durch den Chimera Compiler in folgende Phoenixrelation übersetzt: extensional relation ext_person ( oid( integer, 4, + ), name( atom, 30, - ), vorname( atom, 30, - ) ) Alle extensionalen Relationen werden mit dem Namen der entsprechenden ChimeraObjektklasse und dem Präfix "ext_" benannt. Der in objektorientierten Datenbanksystemen interne Objektidentifikator (OID) wird auf der relationalen Phoenix-Seite durch eine OIDSpalte repräsentiert. Der Wert der OID-Spalte eines Objektes identifiziert das Objekt in der gesamten Datenbank eindeutig. Die extensionale Relation "ext_person" wird von einer abgeleiteten Relation überlagert: derived relation person ( oid( integer, 4, + ), name( atom, 30, - ), vorname( atom, 30, - ) ) person( A, B, C ) <- ext_person( A, B, C ) Alle Anfragen werden nur auf den abgeleiteten Relationen beantwortet. Im Falle einer einzelnen Objektklasse werden die Daten aus der entsprechenden extensionalen Relation komplett übernommen. Dieses Vorgehen bleibt auch bei Klassenhierarchien erhalten. Die Klassenhierarchie bestehend aus obiger Objektklasse "person" und einer Unterklasse "angestellter" wird wie folgt unter Phoenix abgebildet: 35 Inhaltsverzeichnis define object class angestellter superclasses person attributes beruf: string( 40 ), arbeitgeber: string( 100 ) end; extensional relation ext_angestellter ( oid( integer, 4, + ), name( atom, 30, - ), vorname( atom, 30, - ), beruf( atom, 40, - ), arbeitgeber( atom, 100, - ) ) derived relation angestellter ( oid( integer, 4, + ), name( atom, 30, - ), vorname( atom, 30, - ), beruf( atom, 40, - ), arbeitgeber( atom, 100, - ) ) angestellter( A, B, C, D, E ) <ext_angestellter( A, B, C, D, E ) Die Definition der zur "person" gehörenden Sicht wird durch folgende zweite Populationsregel erweitert: person( A, B, C ) <- ext_angestellter( A, B, C, D, E ) Die zweite Populationsregel stellt alle "personen"-relevanten Daten der Angestellten der abgeleitete Relation "person" zur Verfügung. Diese zusätzlichen Regeln stellen sicher, daß alle Anfragen über der vollständigen Menge an Objekten ausgeführt werden. Das oben beschriebene Vorgehen für extensionale Objektklassen kann also wie folgt zusammengefaßt werden: 1. Übersetze alle Attribute einer Objektklasse, inklusive der von den Superklassen geerbten Attribute, in eine entsprechende extensionale Phoenix-Relation mit einer zusätzlichen OID-Spalte. Der Name der extensionalen Relation wird aus dem Präfix "ext_" und dem Namen der Chimera-Objektklasse zusammengesetzt. 2. Erzeuge eine abgeleitete Relation, die alle Attribute der extensionalen Relation besitzt. Der Name der abgeleiteten Relation ist identisch mit dem Namen der Chimera-Objektklasse. 3. Erzeuge eine Populationsregel, die alle Instanzen der extensionalen Relation in die abgeleitete Relation überführt. 36 Inhaltsverzeichnis 4. Erzeuge gemäß der Chimera-Klassenhierarchie weitere Populationsregeln, die alle Werte der an die Unterklassen vererbten Attribute der abgeleiteten Relation zur Verfügung stellen. Abgeleitete Attribute extensionaler oder abgeleiteter Objektklassen werden in eine binäre, abgeleitete Phoenixrelation übersetzt. Der Name der Relation setzt sich aus dem Namen der Objektklasse und dem Namen des abgeleiteten Attributes zusammen. Das erste Attribut der abgeleiteten Relation verwaltet immer den Objektidentifikator des jeweiligen Objektes der Klasse. Das zweite Attribut stellt dann das abgeleitete Attribut zur Verfügung. define object class angestellter superclasses person attributes beruf: string( 40 ), arbeitgeber: string( 100 ), einkommen: integer derived end; Das abgeleitete Attribut "einkommen" wird basierend auf obigem Vorgehen in folgende abgeleiteten Relation übersetzt: derived relation angestellter_einkommen ( oid( integer, 4, + ), einkommen( integer, 8, + ) ) In einer Klassenhierarchie können sowohl für extensionale als auch für abgeleitete Objektklassen abgeleitete Attribute definiert werden. Beide Arten von Klassen können die Berechnungsregeln für bereits definierte Attribute verändern und damit eine Redefinition durchführen. Entscheidend für die genaue Berechnung eines abgeleiteten Attributes ist also die Definition, die in der "most specific class" (in der am meisten spezialisierten Klasse) eines Objektes definiert wurde. Folgendes Beispiel erweitert obige Klassenhierarchie: define object class professor superclasses derived angestellter attributes einkommen: integer redefined end; Durch die Redefinition des Attributes "einkommen" in der Objektklasse "professor" werden die Gehälter für Angestellte und Professoren unterschiedlich berechnet. Die Objekte der Objektklassen werden zusätzlich nach der am stärksten spezialisierten Klasse geordnet. Die Objektidentifikatoren der Objekte werden in folgenden abgeleiteten Relationen zusammengefaßt: 37 Inhaltsverzeichnis derived relation msc_person( oid( integer, 4 + ) ) derived relation msc_angestellter( oid( integer, 4 + ) ) derived relation msc_professor( oid( integer, 4 + ) ) Die abgeleiteten Relationen werden durch folgende Populationsregeln definiert: msc_person( A ) <- ext_person( A, B, C ) msc_angestellter( A ) <ext_angestellter( A, B, C, D, E ), not exists [F, G, H, I] : professor( A, F, G, H, I ) msc_professor( A ) <- professor( A, B, C, D, E ) Im obigen Beispiel ist nur die Definition der Populationsregel für die Relation "msc_angestellter" interessant: In dieser Klasse werden die Objektidentifikatoren für alle Angestellten gesammelt, die keine Professoren sind, da das Einkommen von Professoren auf eine andere Art und Weise berechnet wird. Die eigentliche Berechnung des abgeleiteten Attributs "einkommen" wird durch folgende Regeln erreicht: angestellter_einkommen( A, B ) <msc_angestellter( A ), '$berechne_angestellter_einkommen( A, B )' angestellter_einkommen( A, B ) <professor_einkommen( A, B ) professor_einkommen( A, B ) <msc_professor( A ), '$berechne_professor_einkommen( A, B )' Die beiden Funktionen "$berechne_professor_einkommen" und "$berechne_ professor_einkommen" entsprechen der jeweiligen Übersetzung des deklarativen Ausdrucks der Chimera-Attributpopulationsregel und liefern den jeweiligen Wert für das Einkommen des Angestellten oder Professors. Die zweite Regel zur Berechnung des Einkommens eines Angestellten ist nötig, da Anfragen an die Objektklasse "angestellte" natürlich auch die Daten von Objekten der Klasse "professoren" beinhalten können. 3.3.3 Integritätsbedingungen Integritätsbedingungen werden durch den Chimera Compiler in abgeleitete PhoenixRelationen übersetzt. Dieses Vorgehen wird durch die Tatsache motiviert, daß Integritätsbedingungen in Chimera durch deduktive Regeln definiert werden. Die Idee hinter diesem Vorgehen ist folgende: Falls ein Datenbankzustand eine Integritätsbedingung verletzt, so läßt sich mindestens ein Datensatz in einer abgeleiteten Relation durch die Populationsregeln erzeugen. 38 Inhaltsverzeichnis define object class angestellter superclasses person attributes beruf: string( 40 ), arbeitgeber: string( 100 ), einkommen: integer derived constraints zu_geringes_einkommen ( Self : angestelter, Einkommen : integer ) end; Die Integritätsbedingung obiger "angestellten"-Objektklasse wird durch den Chimera Compiler in eine abgeleitete Relation namens "angestellter$zu_geringes_ einkommen" übersetzt. Die Populationsregel für diese abgeleitete Relation entspricht der Übersetzung des deklarativen Ausdrucks der Implementation der Chimera-Integritätsbedingung. Um die Überprüfung aller in der Datenbank definierter Integritätsbedingungen zu vereinfachen, wird bei der Übersetzung eines Chimera-Schemas nach Phoenix eine zentrale, abgeleitete Relation angelegt, die alle Integritätsbedingungen überprüft. derived relation '$chimera_inconsistent' ( class( atom ), constraint( term ) ) Die binäre Relation enthält den Namen der Klasse, deren Instanz eine Integritätsbedingung verletzt, den Namen der Integritätsbedingung, den Objektidentifikator und den jeweiligen Wert. Eine Populationsregel zur Überprüfung einer Integritätsbedingung hat folgendes Aussehen: '$chimera_inconsistent' ( angestellter, zu_geringes_einkommen( Oid, Einkommen ) ) <- angestellter$zu_geringes_einkommen( Oid, Einkommen) Das CPT überprüft am Ende jeder Transaktion, ob mindestens ein Datensatz in obiger Relation hergeleitet werden konnte. Falls dies der Fall ist, wird die gesamte Transaktion entweder zurückgesetzt, alle Änderungen der Transaktion werden rückgängig gemacht, oder ein entsprechender Trigger wird zur Reparatur des inkonsistenten Datenbestandes ausgeführt. Das jeweilige Ergebnis der Auswertung der Integritätsbedingungen wird dem Benutzer des CPTs auf dem Bildschirm ausgegeben. 39 Inhaltsverzeichnis Andrea Scheuber 4 Oracle8 Dieses Kapitel behandelt das objekt-relationale Datenbanksystem Oracle8. Es werden die alten relationalen Konzepte von Oracle7 und die neuen relationalen Konzepte von Oracle8 vorgestellt. Des weiteren werden die objektorientierten Konzepte von Oracle8 eingeführt und erklärt, in welchen Bereichen sie sinnvoll eingesetzt werden können und welchen Einschränkungen sie in dieser Version unterliegen. Des weiteren werden einige der Oracle-spezifischen Erweiterungen des SQL-92-Standards kurz vorgestellt. Als Grundlage für den allgemeinen Abschnitt 4.1 diente das Buch "Datenbanksysteme: Eine Einführung" von Alfons Kemper und André Eickler [KE99]. Für die weiteren Abschnitte, die das Datenbanksystem Oracle8 vorstellen, wurden hauptsächlich Informationen aus der Online-Dokumentation zu Oracle8 [Ora98] verwendet. Als weitere Informationsquelle diente das Buch "Oracle8 Design Tips" von Dave Ensor und Ian Stevenson [DS97]. 4.1 Datenbanksysteme und Datenmodelle Ein Datenbanksystem (DBS) besteht aus einer Datenbasis (DB) und einem Datenbankmanagementsystem (DBMS). Die Datenbasis dient zur Speicherung der Daten innerhalb eines Datenbanksystems. Ein Datenbanksystem kann mehrere Datenbasen besitzen, die voneinander getrennt durch das DBMS verwaltet werden. Das DBMS eines Datenbanksystems besteht aus Programmen, die Verwaltungsprozesse auf dem Datenbestand der Datenbasis organisieren. Diese Verwaltungsprozesse dienen dazu, die Strukturbeschreibung der Datenbasis anzulegen, Manipulationen am Datenbestand durchzuführen, Anfragen über der Datenbasis auszuwerten und dafür zu sorgen, daß die Datenbank sich immer in einem legalen Zustand befindet. Des weiteren werden vom DBMS Zugriffsrechte, die zur Gewährleistung der Datensicherheit dienen, verwaltet und überprüft. 40 Inhaltsverzeichnis Ein Datenbankmanagementsystem kann in drei Abstraktionsebenen unterteilt werden. Auf interner Ebene wird festgelegt, wie die Daten physikalisch gespeichert werden. Auf konzeptioneller Ebene wird durch das Datenbankschema festgelegt, in welchen Strukturen die Daten in der jeweiligen Datenbasis verwaltet werden. Auf externer Ebene können die Daten durch die Definition von Sichten in einer anderen Struktur präsentiert werden, die den jeweiligen Bedürfnissen der Benutzer entspricht. Die konzeptionelle Ebene eines DBMS wird durch das zugrundeliegende Datenmodell beschrieben. Das Datenmodell liefert die Konstrukte zur Abbildung der realen Welt und stellt für diesen Zweck sowohl die Datendefinitionssprache (engl. data definition language, DDL), als auch die Datenmanipulationssprache (engl. data manipulation language, DML) zur Verfügung. Die zwei hauptsächlich verwendeten Klassen von Datenmodelle sind das relationale Datenmodell und unterschiedliche objektorientierte Datenmodelle. In den folgenden Abschnitten werden die wichtigsten Eigenschaften beider Modelltypen vorgestellt. Das relationale Datenmodell stellt Gegenstände aus der realen Welt, die auch als Entitäten bezeichnet werden, in Form von Relationen dar. Eine n-stellige Relation R ist mathematisch gesehen eine Teilmenge des kartesischen Produktes von Mengen M1, ... Mn: R ⊆ M1 × M2 × ... × Mn Eine solche Relation kann auch in Form einer zweidimensionalen Tabelle dargestellt werden, und als solche wird sie auch im relationalen Datenmodell bezeichnet. Ein Unterschied zwischen einer Tabelle und einer Relation besteht darin, daß durch eine Tabelle eine Multimenge abgebildet werden kann, da innerhalb einer Tabelle Duplikate zulässig sind, falls nicht ein eindeutiger Schlüssel (Primärschlüssel) dies verhindert. Im folgenden werden die Begriffe Tabelle und Relation synonym verwendet, da davon ausgegangen wird, daß eine Tabelle auch immer einen Primärschlüssel besitzt. Falls dies einmal nicht der Fall sein sollte wird an dieser Stelle explizit darauf hingewiesen. Eine Zeile in einer Tabelle wird auch als Tupel oder Datensatz bezeichnet, da sie alle Attribute einer Relation zu einer Einheit zusammenfaßt. Die Spalten einer Tabelle werden durch einen eindeutigen Attributnamen bezeichnet und durch einen Wertebereich definiert. Als Wertebereich stehen unterschiedliche atomare Datentypen zur Verfügung. Der zulässige Wertebereich von Attributen kann, durch den Einsatz von Integritätsbedingungen, noch genauer spezifiziert bzw. eingeschränkt werden. Die Aufgabe von Integritätsbedingungen ist es, zu überprüfen, ob sich die Datenbank in einem legalen Zustand befindet. Diese Überprüfungen werden durch DML-Anweisungen ausgelöst, die Änderungen am Datenbestand vornehmen. Verstoßen die Änderungen gegen Integritätsbedingungen, so werden sie nicht ausgeführt, um den legalen Zustand der Datenbank zu wahren. Mit Hilfe einer Integritätsbedingung kann zum Beispiel gefordert werden, daß die Schlüsselattribute zweier Tabellen nur identische Werte enthalten dürfen. Eine solche Integritätsbedingung wird Fremdschlüsselbedingung (engl. foreign key constraint) genannt. Wird nun eine Anfrage über diesen beiden Tabellen ausgewertet, können die Werte der Schlüsselattribute dazu benutzt werden, die Datensätze zueinander in Beziehung zu setzen. In der Datenbanktheorie existiert nur ein relationales Datenmodell aber mehrere objektorientierte Modelle. Ein objektorientiertes Datenmodell stellt Entitäten aus der realen Welt in Form von Objekten dar. Ein Objekt ist ein Informationsträger, der alle Eigenschaften eines Gegenstandes aus der realen Welt durch seine Struktur und sein Verhalten repräsentiert. Ein Objekt besteht aus Attributen, die eine Strukturbeschreibung der Instanzen eines Objektes bilden und Beziehungen zu anderen Objekten herstellen können, da ein Attribut auch ein beliebiges Ob41 Inhaltsverzeichnis jekt sein kann und nicht auf atomare Datentypen beschränkt ist. Die Verhaltensbeschreibung der Instanzen eines Objektes sind innerhalb einer Objektklasse durch eine Menge von Operationen definiert. Eine weitere wichtige Eigenschaft von Objektklassen ist der Vererbungsmechanismus, der dazu dient die Struktur und die Verhaltensweisen zu generalisieren oder zu spezialisieren. Die konzeptionelle Ebene des Datenbanksystem Oracle8 beinhaltet sowohl objektorientierte als auch relationale Konzepte und wird deshalb von Oracle als objekt-relational bezeichnet. Allerdings ist Oracle8, allein durch seine Entwicklung aus dem relationalen DBMS Oracle7 bedingt, in erster Linie ein relationales System, das durch objektorientierte Modellierungskonzepte erweitert worden ist. Diese Erweiterung beschränkt sich auf grundlegende Konzepte der Objektorientierung und verzichtet auf wesentliche Eigenschaften wie zum Beispiel den Vererbungsmechanismus. Des weiteren ist der Einsatz einiger objektorientierten Konstrukte in Bezug auf ihre Schachtelungstiefe stark eingeschränkt. Das objekt-relationale DBMS Oracle8 ist als ein erster Versuch zu betrachten, objektorientierte Konzepte in ein relationales Datenmodell zu integrieren. 4.2 Die relationalen Konzepte von Oracle8 In diesem Abschnitt werden die relationalen Konzepte von Oracle8 vorgestellt, die innerhalb einer Schemadefinition verwendet werden können. Diese Konzepte werden im folgenden auch als Schemaelemente bezeichnet. Angefangen wird bei den sogenannten Built-inDatentypen (vom DBS vordefinierte Datentypen), die von Oracle8 zur Verfügung gestellt werden. Diese Datentypen sind keine Schemaelemente, sondern bilden die Grundlage zur Definition von Attributen in Schemaelementen, indem sie die vordefinierten Wertebereiche zur Verfügung stellen. Die eigentlichen relationalen Konzepte sind die Tabellen und Sichten, die mit Hilfe von Integritätsbedingungen die Struktur einer Entität abbilden. Zur Abbildung des Verhaltens einer Entität dienen im relationalen Modell Trigger, die an eine Tabelle angehängt werden. Weitere Hilfsmittel sind Prozeduren und Funktionen, die aus Triggern oder aber aus einer Applikation heraus aufgerufen werden können. 4.2.1 Built-in-Datentypen Die Built-in-Datentypen von Oracle8 werden zur Definition der Wertebereiche von Attributen in Schemaelementen benutzt. Des weiteren werden sie zur Definition von Variablen in PL/SQL benutzt, der internen Programmiersprache von Oracle8. Mit der Hilfe von PL/SQL können zum Beispiel interne Prozeduren, Funktionen und Trigger definiert werden. Die folgenden Datentypen sind die grundlegenden Datentypen, die sowohl unter Oracle7 als auch Oracle8 zur Verfügung stehen. Der Datentyp "character(n)" legt den Wertebereich einer Variablen oder eines Attributes fest, der als Wert eine Zeichenkette akzeptiert, die aus exakt n Zeichen besteht. Wird eine zu kurze Zeichenkette in die Tabelle eingefügt, werden die fehlenden Stellen durch Leerzeichen aufgefüllt. Ist die Zeichenkette zu lang, wird eine Fehlermeldung ausgegeben. Die maximale Größe für Zeichenketten vom Typ "character" ist 2000. Die vordefinierte Mindestgröße ist 1, die automatisch vergeben wird, wenn für n kein expliziter Wert spezifi42 Inhaltsverzeichnis ziert wird. Der Wertebereich des Datentyps "char(n)" ist durch den Datentyp "character(n)" definiert und besitzt keinerlei Einschränkungen. Beide Datentypen können synonym verwendet werden. Der Datentyp "varchar2(n)" legt den Wertebereich einer Variablen oder eines Attributes fest, der als Wert eine Zeichenkette variabler Länge akzeptiert, die maximal 4000 Zeichen lang sein kann. Die maximale Länge n muß bei der Definition des Attributes angegeben werden und muß mindestens 1 sein. Der Datentyp "varchar(n)" ist momentan noch synonym mit dem Datentyp "varchar2(n)" verwendbar. In der Oracle8-Online Hilfe wird empfohlen den Datentyp "varchar" nicht zu verwenden, denn in späteren Versionen soll aus "varchar" ein eigener Datentyp mit variabler Länge werden, der anderen Vergleichsoperationen unterliegen soll, als der Datentyp "varchar2". Der Datentyp "date" wird benutzt, um Informationen über Datum und Uhrzeit abzuspeichern. Zu diesen Informationen gehören das Jahr, der Monat, der Tag, die Stunde, die Minute und die Sekunde. Ein gültiges Datum bewegt sich innerhalb der Zeitspanne vom 1. Januar 4712 v. Chr. bis zum 31. Dezember 4712 n. Chr. Der Datentyp "number(v,n)" wird benutzt, um numerische Werte in der Datenbank abzulegen. Werden die Variablen v und n bei der Definition eines Wertebereichs nicht verwendet, so werden nur natürliche Zahlen als Werte akzeptiert. Soll der Wertebereich auch reelle Zahlen als Werte zulassen, so muß die Anzahl der Vorkommastellen durch die Variable v und die Anzahl der Nachkommastellen durch die Variable n spezifiziert werden. Für v können Werte zwischen 1 und 38 benutzt werden. Der Werte von n darf sich zwischen –84 und 127 bewegen. Eine negative Angabe kann zur Definition sehr großer Zahlen verwendet werden. Für die interne Programmiersprache PL/SQL stehen zusätzlich die Datentypen "integer" und "real" zur Verfügung. Der Datentyp "long" wird dazu benutzt, Zeichenketten variabler Länge zu speichern. Der Speicherplatz, den die Zeichenkette belegen darf, liegt bei maximal zwei Gigabytes, vorausgesetzt dieser Speicherplatz steht auf dem jeweiligen Datenbankserver zur Verfügung. Die Nutzung dieses Datentyps unterliegt den folgende Einschränkungen. Eine Tabelle darf nur eine Spalte des Datentyps "long" beinhalten, über die nur die Integritätsbedingung "not null" definiert werden kann. Des weiteren kann kein Index über diese Spalte gelegt werden. Die Datentypen "raw" und "long raw" werden dazu benutzt, binäre Daten zu speichern, die nicht vom Datenbanksystem interpretiert werden müssen. Bei diesen Daten kann es sich zum Beispiel um Bilder, Musik oder Dokumente handeln. Die folgenden Built-in-Datentypen sind neue Datentypen von Oracle8 und werden allgemein als "lob"s (engl. large objects) bezeichnet. "lob"s sind Datentypen die zur Speicherung großer und unstrukturierter Datenmengen bis zu einer Größe von vier Gigabytes verwendet werden. Es ist möglich die Daten von "lob"s durch DML-Operationen zu modifizieren. Es gibt drei unterschiedliche Typen von "lob"s. Der Datentyp "blob" wird benutzt, um große Objekte bestehend aus binären Daten zu speichern. Der Datentyp "clob" wird benutzt, um 43 Inhaltsverzeichnis große Objekte bestehend aus single-byte Zeichen zu speichern. Der Datentyp "nclob" wird benutzt, um große Objekte bestehend aus multi-byte Zeichen mit fester Länge zu speichern. Ein weiterer neuer Built-in-Datentyp ist der Datentyp "bfile". Er dient dazu, auf Binärdateien außerhalb des Datenbanksystems zugreifen zu können. Ein Attribut, daß als Wertebereich den Datentyp "bfile" besitzt, speichert einen Zeiger, der die Adresse der Binärdatei beinhaltet. Der Inhalt der Binärdatei ist nicht durch Oracle-DML-Operationen modifizierbar, da nur lesender Zugriff auf die Datei erlaubt ist. Eine Besonderheit der hier vorgestellten Datentypen ist es, daß der Wert "null" für alle definiert ist. Das heißt, es ist möglich jedem Datentypen einen Nullwert zuzuweisen, der sich in seiner Bedeutung von Leerstrings für Zeichenketten und dem Wert 0 für numerische Werte unterscheidet und einen nicht initialisierten Attributwert kennzeichnet. 4.2.2 Tabellen Die Tabellen sind das grundlegende, relationale Konzept zur Speicherung und Organisation von Daten. Sie stellen in ihrer Gesamtheit die Datenbasis eines Datenbanksystems dar. Eine Tabelle besitzt einen Namen, durch den sie innerhalb des Datenbankschemas eindeutig identifiziert werden kann. Die Spalten der Tabelle bestehen aus Attributen, die innerhalb der Tabelle einen eindeutigen Namen besitzen und deren Wertebereich durch einen Datentyp festgelegt wird. Als Wertebereich stehen die Built-in-Datentypen von Oracle zur Verfügung. Eine neue Option von Oracle8 ist die Möglichkeit, einen benutzerdefinierten Datentyp (siehe Abschnitt 4.3.1) zu definieren und als Wertebereich für ein Attribut zu verwenden. 4.2.3 Sichten Eine Sicht (View) repräsentiert ausgesuchte Daten, die aus Tabellen oder bereits definierten Sichten zusammengestellt werden. Eine Sicht beinhaltet das Ergebnis einer Anfrage und kann somit als virtuelle Tabelle bezeichnet werden. Unter bestimmten Voraussetzungen ist es möglich, Modifikationen an dem Datenbestand einer Sicht (View Update) vorzunehmen. Diese Modifikationen werden nicht an dem virtuellen Datenbestand einer Sicht vorgenommen, sondern am Datenbestand der Tabellen, aus denen die Attribute der Sicht stammen. Besteht eine Sicht nur aus Attributen, die aus einer Anfrage an eine einzige Tabelle stammen und ist auch der Primarschlüssel der Tabelle Bestandteil der Sicht, so werden die Daten automatisch der richtigen Tabelle zugeordnet und eingefügt, aktualisiert oder gelöscht. Besitzt eine Sicht Attribute, die aus mehreren Tabellen stammen, so ist Oracle8 nicht mehr in der Lage, die erforderlichen Modifikationen selbständig an den betroffenen Tabellen durchzuführen, wenn mehrere Attribute aus unterschiedlichen Tabellen gleichzeitig betroffen sind. Die Attribute, die Schlüsselwerte enthalten und dazu dienen die Beziehungen zwischen den Tabellen herzustellen (join keys), dürfen auch nicht verändert werden, um die bereits bestehenden Beziehungen zwischen den Daten der Tabellen zu erhalten. Will man trotzdem nicht darauf verzichten, Modifikationen am Datenbestand von Sichten durchzuführen, so ist man auf das neue Oracle8-Konzept der Instead-of-Trigger (siehe Abschnitt 4.2.5) angewiesen, die ausschließlich für Sichten definiert werden können. 44 Inhaltsverzeichnis 4.2.4 Integritätsbedingungen Integritätsbedingungen (engl. integrity constraints) sorgen dafür, daß sich die Datenbank in einem legalen Zustand befindet. Es werden fünf verschiedene Arten von Built-inBedingungen zur Verfügung gestellt, die bei der Schemadefinition verwendet werden können. Wenn es erforderlich ist, speziellere Integritätsbedingungen innerhalb eines Datenbankschemas zu erstellen, die mit den folgenden Built-in-Bedingungen nicht modelliert werden können, so ist man gezwungen auf andere Konzepte, wie Trigger, Prozeduren oder Funktionen zurückzugreifen. Die Attribute einer Datenbanktabelle können mit einer Integritätsbedingung vom Typ "not null" belegt werde, um zu garantieren, daß in jedem Datensatz dieser Tabelle der Wert dieser Attribute einen gültigen Wert, der ungleich dem Wert "null" ist, beim Einfügen zugewiesen bekommt. Die Attribute einer Datenbanktabelle können mit einer Integritätsbedingung vom Typ "unique" belegt werden, um zu garantieren, daß dieser Wert für diese Attribute innerhalb aller Datensätze der Tabelle eindeutig sind. Eine Integritätsbedingung vom Typ "primary key" definiert den Primärschlüssel, der einen Datensatz innerhalb einer Tabelle eindeutig identifiziert. Dieser Schlüssel kann auch aus mehreren Attributen der Tabelle bestehen, die zusammen einen eindeutigen Schlüssel bilden. Eine Integritätsbedingung vom Typ "primary key" impliziert eine Integritätsbedingung vom Typ "not null" für alle am Primärschlüssel beteiligten Attribute. Das bedeutet, daß alle Attribute eines Primärschlüssels in einem Datensatz einen gültigen Wert besitzen müssen. Eine Integritätsbedingung vom Typ "foreign key" definiert einen Fremdschlüssel einer Tabelle, der benutzt wird, um die Beziehungen zwischen den Tupeln in den Datenbanktabellen zu definieren und zu überprüfen, ob sie eingehalten werden. Es existieren drei unterschiedliche Beziehungstypen, die mit Hilfe der bereits vorgestellten Integritätsbedingungen realisiert werden können. Mit dem Beziehungstyp 1:1 bezeichnet man eine Verbindung zwischen zwei Tabellen, die einem Datensatz in der ersten Tabelle genau einen Datensatz in der zweiten Tabelle zuordnet. Der Beziehungstyp 1:n ermöglicht es einem Datensatz in der ersten Tabelle mehrere Datensätze in der zweiten Tabelle zuzuordnen. Der Beziehungstyp n:m ermöglicht es, daß sowohl ein Datensatz in der ersten Tabelle in Verbindung mit mehrere Datensätzen der zweiten Tabelle steht als auch umgekehrt. Eine n:m-Beziehung ist unter Oracle nur möglich durch die Simulation einer zusätzlichen Tabelle mit jeweils einer n:1 und einer 1:m Beziehung. Eine "check"-Bedingung ist ein boolscher Ausdruck, der über dem Wertebereich eines Attributs in einer Datenbanktabelle definiert wird. Dabei kann die Bedingung nur auf die alten und die neuen Werte eines manipulierten Datensatzes zugreifen. Es dürfen keine Prozeduren oder Funktionen benutzt oder Anfragen an die Datenbank gestellt werden, um den boolschen Ausdruck auszuwerten. In Oracle7 ist es bereits möglich Integritätsbedingungen zu aktivieren und deaktivieren. Dabei muß allerdings beachtet werden, daß keiner der bereits existierenden Datensätze gegen diese Integritätsbedingung verstoßen darf, wenn sie aktiviert werden soll. Um diese Problem zu 45 Inhaltsverzeichnis umgehen, ist es in Oracle8 jetzt möglich durch den folgenden Ausdruck eine Integritätsbedingung zu aktivieren, ohne auf bereits bestehende Datensätze Rücksicht zu nehmen. ALTER TABLE table_name ENFORCE CONSTRAINT constraint_name; Beispiel 4.2.1: Aktivierung einer Integritätsbedingung Nur neu eingefügte Datensätze unterliegen dieser Integritätsbedingung nach ihrer Aktivierung. Die alten Datensätze, die der Integritätsbedingung nicht entsprechen, werden einfach ignoriert. Eine zusätzliche Erweiterung von Oracle8 ist es, daß Integritätsbedingungen verzögert am Transaktionsende überprüft werden können. Diese Vorgehensweise ist erforderlich, wenn Integritätsbedingungen fordern, daß zu einem Eintrag in der ersten Tabelle ein Eintrag in der zweiten Tabelle existieren muß und umgekehrt. Wenn diese Integritätsbedingungen nicht verzögert am Transaktionsende überprüft werden, dann kann in keiner der beiden Tabellen ein Datensatz eingefügt werden, da immer eine Integritätsbedingung verletzt ist. Durch den folgenden Ausdruck kann eine Integritätsbedingung so definiert werden, daß sie verzögert ausgeführt wird. SET CONSTRAINTS constraint_name DEFERRED; Beispiel 4.2.2: Veränderung des Ausführungsmodus einer Integritätsbedingung Ersetzt man den Namen der Integritätsbedingung durch das Schlüsselwort "all", so werden alle Integritätsbedingungen des Schemas verzögert (engl. deferred) überprüft. Umgekehrt ist es auch möglich eine Integritätsbedingung so zu definieren, daß sie sofort (engl. immediate) überprüft wird. Das Schlüsselwort "deferred" wird in diesem Fall durch das Schlüsselwort "immediate" ersetzt. Standardmäßig sind Integritätsbedingungen so definiert, daß sie sofort überprüft werden und nicht erst am Ende einer Transaktion. 4.2.5 Trigger Ein Trigger ist eine aktive Regel, die durch einen spezifizierten Ereignistyp ausgelöst wird. In Oracle8 wird zwischen den drei Ereignistypen INSERT, UPDATE und DELETE unterschieden, die zur Kategorie der DML-Operationen gehören. Ein Trigger ist in Oracle8 immer an eine Tabelle oder eine Sicht (siehe Abschnitt 4.2.3) gebunden. Tritt nun der im Trigger spezifizierte Ereignistyp bzgl. der Tabelle auf, so wird der Trigger ausgelöst und führt seine Aktionen aus, die zum Beispiel zur Erhaltung des korrekten Datenbestandes oder zur Datengewinnung beitragen können. Innerhalb der Triggerdefinition wird nicht nur durch ein spezifiziertes Ereignis der Typ des Triggers festgelegt. Hier wird auch zwischen dem sogenannten "row-level"-Trigger und 46 Inhaltsverzeichnis dem "statement-level"-Trigger unterschieden. Ein "row-level"-Trigger ist ein Trigger, der für jeden Datensatz, der durch das spezifizierte Ereignis beeinträchtigt wird, ausgelöst wird. Ein "statement-level"-Trigger wird nur einmal pro spezifiziertes Ereignis ausgeführt. Das bedeutet, daß es egal ist wie viele Datensätze betroffen sind. Im Prinzip sind die Datenbanktrigger von Oracle8 Prozeduren. Der eigentliche Unterschied zwischen einer Prozedur und einem Trigger besteht darin, daß ein Trigger implizit vom DBMS Oracle8 ausgeführt wird, während eine Prozedur explizit von den Benutzern, Applikationen oder Triggern aufgerufen wird. Ein Trigger wird separat von den Tabellen im Schema gespeichert. Ein neues Konzept von Oracle8 sind die Instead-of-Trigger. Ihre Aufgabe ist es, bei einer Modifikation am Datenbestand einer Sicht (engl. view update) die Veränderungen der einzelnen Attributwerte in den Sichten auf die Attributwerte der unterschiedlichen Basistabellen zu übertragen. Die Anwendung der Instead-Of-Trigger ist auf das Konzept der Sichten (views, object views) beschränkt. Instead-of-Trigger sind immer Row-Level-Trigger und können jeweils für die drei Ereignistypen "insert", "update" und "delete" definiert werden. Auf diese Weise wird es ermöglicht, das Verhalten eines "view updates" nicht vom DBMS steuern zu lassen, sondern selbst zu bestimmen, wie der Datenbestand modifiziert werden soll, um zu garantieren, daß sich die Datenbank auch nach dem View-Update in einem legalen Zustand befindet. Zu beachten ist bei der Definition von Sichten und Instead-ofTriggern, daß für Sichten, die auf Sichten mit Instead-of-Triggern basieren, ebenfalls Insteadof-Trigger definiert werden müssen. 4.2.6 Interne Prozeduren und Funktionen Benutzerdefinierte interne Prozeduren und Funktionen werden in einem OracleDatenbanksystem in der prozeduralen Spracherweiterung von SQL (PL/SQL) realisiert und innerhalb der jeweiligen Datenbank gespeichert, in deren Schema sie definiert worden sind. Sie können aus Triggern, vom SQL-Interface oder aus Applikationen direkt aufgerufen werden. Ein Paket (engl. package) ist eine Kollektion von Prozeduren und Funktionen, die eine Einheit bildet und auch als solche in der Datenbank gespeichert wird und Applikationen zur Verfügung gestellt werden kann. Die Definition von Prozeduren, Funktionen und Paketen erfolgt über einen Spezifikationsteil, der das Interface zwischen den aufrufenden Programmsequenzen und dem Programmcode der Prozeduren bildet. Der sogenannte Body realisiert die eigentliche Implementierung der Prozeduren und Funktionen. Bei der Spezifikation von Parametern ist zu beachten, daß Oracle verschiedene Typen von Parametern zur Verfügung stellt, die sogenannten "in"-, "out"- und "in-out"Parametern. Jeder dieser Typen besitzt unterschiedliche Eigenschaften, die sie für unterschiedliche Aufgabenbereiche qualifizieren. Wird der Parametertyp bei der Spezifikation nicht mit angegeben, so wird der Parameter automatisch als "in" Parameter klassifiziert. Ein "in"-Parameter wird verwendet, um einen Wert an Unterprogramme (Funktionen, Prozeduren) zu übergeben. Seine Eigenschaften ähneln innerhalb eines Unterprogramms den Eigenschaften einer Konstante, da der Wert eines "in"-Parameters weder modifiziert noch nach außen an den Aufruf seines Unterprogramms zurückgegeben werden kann. Der Übergabeparameter eines spezifizierten "in"-Parameters kann eine Konstante, eine initialisierte Variable oder ein Ausdruck sein. 47 Inhaltsverzeichnis Ein "out"-Parameter wird verwendet, um einen Wert an den Aufruf des Unterprogramms zurückzuliefern. Seine Eigenschaften ähneln innerhalb eines Unterprogramms den Eigenschaften einer nicht initialisierten Variablen. Der Übergabeparameter eines spezifizierten "out"-Parameters muß eine Variable sein. Diese Variable darf durchaus mit einem Wert initialisiert sein, der allerdings bei dem Aufruf des Unterprogramms verloren geht und durch den Wert "null" ersetzt wird. Ein "out"-Parameter darf nur einen Wert zugewiesen bekommen und kann innerhalb eines Unterprogramms nicht dazu benutzt werden, einer anderen Variablen seinen Wert zuzuweisen. Des weiteren darf er auch nicht innerhalb eines Ausdrucks benutzt werden, um einen Wert zu definieren. Ein "in-out"-Parameter wird verwendet, um einen Wert an Unterprogramme zu übergeben, ihn innerhalb der Unterprogramme zu aktualisieren und den aktualisierten Wert an den Aufruf zurückzugeben. Seine Eigenschaften ähneln den Eigenschaften einer initialisierten Variablen, da es möglich ist den Wert zu modifizieren und man den Parameter auch in Ausdrucken benutzen kann, die neue Werte deklarieren. Es ist möglich Funktionen und Prozeduren, die zu einem Paket zusammengefaßt sind, zu überladen. Will man Methoden überladen, so muß man darauf achten, daß sie vom gleichen Typ sind. Das bedeutet, daß Funktionen nur mit Funktionen und Prozeduren nur mit Prozeduren überladen werden können. Der gleiche Name kann für Funktionen oder Prozeduren mehrfach verwendet werden, wenn sich die spezifizierten Übergabeparameter in Anzahl, Anordnung oder Datentyp unterscheiden. Datentypen werden nur dann als unterschiedlich erkannt, wenn ihre Wertebereich grundsätzlich verschieden sind. So gehören beispielsweise die Datentypen "char", "varchar", "varchar2" und "long" zu einer Familie von Datentypen, die im Zusammenhang mit Überladen nicht als unterschiedlich erkannt werden, da sie alle zur Speicherung alphanumerische Daten verwendet werden. Das gleiche Problem liegt auch bei den Datentypen "number", "integer" und "real" vor. Wird eine dieser Methoden aufgerufen, wird von PL/SQL die Liste der aktuellen Parameter mit der spezifizierten Parameterliste in den Methoden verglichen. Auf diese Weise wird die richtige Funktion oder Prozedur ausgewählt. Es ist nicht möglich eine Methode zu überladen, deren Parameter sich nur durch ihren Typ ("in" oder "in-out") unterscheiden. Das gleiche gilt auch für Funktionen, die sich nur durch den Datentyp ihres Rückgabewertes unterscheiden. Anhand der folgenden Beispiele wird verdeutlicht, welche Spezifikationen beim Überladen nicht zulässig sind. PROCEDURE Lieferdatum( aktDatum IN DATE ) IS ... PROCEDURE Lieferdatum( aktDatum IN OUT DATE ) IS ... Beispiel 4.2.1: Problem beim Überladen von Prozeduren mit ungleichem Parametertyp Die Prozeduren aus dem vorangestellten Beispiel können sich gegenseitig nicht überladen, da sie sich nur durch den Parametertyp unterscheiden. Dieser Unterschied wird durch das DBMS nicht überprüft und kann deshalb auch nicht berücksichtigt werden. 48 Inhaltsverzeichnis PROCEDURE Preisnachlass( Preis INTEGER ) IS ... PROCEDURE Preisnachlass( Preis REAL ) IS ... Beispiel 4.2.2: Problem beim Überladen von Prozeduren mit Parametern aus der gleichen Datentypfamilie Die Prozeduren aus Beispiel 4.2.1 können sich gegenseitig nicht überladen, da die Datentypen INTEGER und REAL zu der gleichen Datentypfamilie gehören. Das DBMS kann beim Aufruf der Prozedur nicht unterscheiden zur welcher Datentypfamilie der Parameter gehört. FUNCTION Bezahlt( acct_id INTEGER ) RETURN BOOLEAN IS FUNCTION Bezahlt( acct_id INTEGER ) RETURN INTEGER IS Beispiel 4.2.3: Probleme beim Überladen von Funktionen mit Rückgabeparametern Die Prozeduren aus Beispiel 4.2.3 können sich nicht gegenseitig überladen, da sie sich nur durch den Datentyp des Rückgabewertes unterscheiden. Ähnliche Beispiele und weitere Informationen zu diesem Thema sind in der Oracle8-Online-Hilfe zu finden. 4.2.7 Externe Prozeduren und Funktionen Als externe Prozeduren bezeichnet man unter Oracle8 Unterprogramme, die zum Beispiel in C++ implementiert worden sind und in Windows-Betriebssystemen als "Dynamic Link Libraries" (DLL) der SQL-Schnittstelle zur Verfügung gestellt worden sind. Diese externen Prozeduren werden von PL/SQL behandelt, als ob es sich um PL/SQL Unterprogramme handeln würde. Dadurch eignen sie sich, um Schnittstellen zwischen Datenbanken und Applikationen zu gestalten. 4.3 Die objektorientierten Konzepte von Oracle8 In den folgenden Abschnitten werden die neuen Konzepte von Oracle8 vorgestellt, welche die objektorientierte Komponente des DBMS repräsentieren. Im wesentlichen handelt es sich um Elemente, die zur Schemadefinition verwendet werden können und im folgenden auch als Schemaelemente bezeichnet werden. Des weiteren wird erklärt, wie die objektorientierten Konzepte im Zusammenhang mit den relationalen Konzepten genutzt werden können. 49 Inhaltsverzeichnis 4.3.1 Objekttypen Das Schemaelement Objekttyp dient zur Abstraktion einer Entität und kann auf vielfältige Weise bei der Definition eines Datenbankschemas eingesetzt werden. Ein Objekttyp ist ein benutzerdefinierter Datentyp, dessen Attribute sich aus den atomaren Built-in-Datentypen von Oracle8 und bereits innerhalb des Schemas definierten Objekttyps zusammensetzen kann. Er ist als reine Strukturdefinition zu betrachten, die keine Instanzen besitzt. Ein Objekttyp besitzt einen eindeutigen Namen, um ihn innerhalb eines Schemas zu identifizieren. Seine Attribute sind die Strukturbeschreibung einer Entität. Es ist möglich Methoden über einem Objekt zu definieren, um auf diese Weise das Verhalten der Entität nachzubilden. Dieser benutzerdefinierte Datentyp wird je nach Verwendung innerhalb der Definition eines Schemaelements entweder als Spaltenobjekt oder als Zeilenobjekt klassifiziert und kann innerhalb des Schemas, in dem er definiert worden ist, sowohl als Zeilenobjekt als auch als Spaltenobjekt verwendet werden. Der Begriff Spaltenobjekt bezieht sich auf die Attribute eines Schemaelements. Ein Objekttyp, der als Spaltenobjekt bezeichnet wird, definiert die Struktur eines Attributes in einer relationalen Datenbanktabelle oder die Struktur eines Attributes in einem anderen Schemaelement. Der Begriff Zeilenobjekt bezieht sich auf die Instanzen eines Schemaelements. Ein Zeilenobjekt definiert die Struktur eines kompletten Datensatzes bzw. die Struktur der Instanz des Schemaelements. Die Verwendung eines Objekttyps als Zeilenobjekt erfolgt bei der Definition von Objekttabellen auf die im Abschnitt 4.3.3 genauer eingegangen wird. 4.3.1.1 Interne Verwaltung eines Objekttyps als Wertebereich eines Attributs Wenn eine relationale Datenbanktabelle definiert wird, die einen Objekttyp als Wertebereich eines Attributes enthält, dann werden vom DBMS Oracle8 zusätzliche Spalten in diese Tabelle eingefügt, die für den Benutzer nicht sichtbar sind und welche die Struktur des Objekttyps repräsentieren. Diese Spalten bilden die einzelnen Grundkomponenten des Objekttyps in die Tabelle ab. Unter den Grundkomponenten des Objekttyps versteht man die Built-inDatentypen, die Oracle8 zur Verfügung stellt. Eine weitere Spalte wird benötigt, um zu speichern, ob die Instanz des Objekttyps Daten enthält oder nicht. Dies bezeichnet man als die Null- bzw. Existenzinformation der Instanz. Folgendes Beispiel verdeutlicht, wie der Objekttyp auf relationale Weise innerhalb einer Tabelle umgesetzt wird. CREATE TYPE ot_adresse AS OBJECT ( strasse VARCHAR2( 40 ), hausnr NUMBER( 5 ), plz NUMBER( 5 ), land VARCHAR( 20 ) ); 50 Inhaltsverzeichnis CREATE TYPE ot_person AS OBJECT ( name VARCHAR2( 30 ), vorname VARCHAR2( 30 ), geburtstag DATE, adresse ot_adresse ); Beispiel 4.3.1: Definition eines Verschachtelten Objekttyps Hat man also einen solchen verschachtelten Objekttyp definiert, so kann man ihn in einer Baumstruktur wie folgt darstellen: Beispiel 4.3.2: Baumstruktur eines Objekttyps Diese Baumstruktur wird innerhalb einer Tabelle intern in folgende relationale Darstellung überführt, wobei die Attribute p.null und a.null die Spalten sind, die festlegen, ob eine Instanz des Objekttyps innerhalb der Tabelle existiert: p.null p.name p.vorname p.geburtstag a.null a.strasse a.hausnr a.plz a.land Wie aus diesem Beispiel ersichtlich, werden nur die Blätter der Baumstruktur, die aus den Built-in-Datentypen von Oracle8 bestehen, in der Tabelle abgelegt. Somit geht die eigentliche Struktur des Objekttyps in der zweidimensionalen Darstellung verloren, da der Objekttyp in seine atomaren Komponenten zerlegt wird. 51 Inhaltsverzeichnis 4.3.1.2 Methoden Wie schon bereits erwähnt, ist es möglich, für einen Objekttyp Methoden zu definieren. Methoden sind Funktionen oder Prozeduren, die an einen Objekttyp gebunden sind. Die Aufgabe einer Methode ist es, Informationen über die Instanzen der Objekttyps zu beschaffen, indem sie die Daten einer Instanz analysiert und das Ergebnis außerhalb der Instanz dem DBMS und dem Benutzer zur Verfügung zu stellt. Die Methoden eines Objekttyps werden innerhalb seiner Spezifikation deklariert und können auch wie die internen Funktionen und Prozeduren überladen werden (siehe Abschnitt 4.2.6). Der eigentliche Programmcode einer Methode wird im sogenannten "type body" abgelegt. CREATE TYPE ot_adresse AS OBJECT ( strasse VARCHAR2( 40 ), hausnr NUMBER( 5 ), plz NUMBER( 5 ), land VARCHAR( 20 ), MEMBER FUNCTION plz2Stadt(PostLeitZahl IN INTEGER) RETURN VARCHAR2 ); CREATE TYPE BODY ot_adresse IS MEMBER FUNCTION plz2Stadt(PostLeitZahl IN INTEGER) RETURN VARCHAR2 IS StadtName VARCHAR2(20); BEGIN SELECT name INTO StadtName FROM staedte WHERE plz = PostLeitZahl; RETURN StadtName; END; Beispiel 4.3.1: Implementierung einer Methode In diesem Beispiel wird die Funktion "plz2Stadt" benutzt, um zu einer gültigen Postleitzahl den entsprechenden Stadtnamen herauszufinden, der in der Tabelle "staedte" abgelegt ist. Diese Funktion kann z.B. von Applikationen aufgerufen werden, die das Ergebnis weiter verwenden können. Bei der allgemeinen Spezifikation von Parametern muß auch, wie bei Funktionen und Prozeduren, auf den Typ des Parameters geachtet werden (siehe Abschnitt 4.2.6). Ein spezieller Parameter in Methoden ist der Parameter "self", der den direkten Zugriff auf eine Instanz eines Objekttyps ermöglicht. Dieser Parameter steht in jeder Methode zur Verfügung und braucht normalerweise nicht explizit spezifiziert zu werden. Bei Funktionen ist der Parameter "self" automatisch ein "in"-Parameter, bei Prozeduren ein "in-out"-Parameter. Wenn 52 Inhaltsverzeichnis der Parameter "self" explizit in der Spezifikation der Methode festgelegt werden soll, z.B. um ihn innerhalb einer Funktion als "in-out"-Parameter zu klassifizieren, so ist zu beachten, daß "self" immer der erste Parameter sein muß, der angegeben wird. 4.3.1.3 Die Vergleichsfunktionen MAP und ORDER Es existiert unter Oracle8 die Möglichkeit die sogenannten Vergleichsfunktionen "map" und "order" für Objekttypen zu definieren. Diese werden benutzt, um die Instanzen eines Objekttyps untereinander zu vergleichen. Eine dieser Funktionen sollte vom Benutzer definiert werden, da ansonsten nur die Möglichkeit besteht, die Instanzen eines Objekttyps auf Gleichheit oder Ungleichheit zu prüfen, indem man alle korrespondierende Attributwerte überprüft. Sind diese Attributwerte identisch, so werden die Instanzen als gleich interpretiert. Der Nachteil dieser Vorgehensweise ist es, daß bei Ungleichheit keine Aussage über die Wertigkeit der Instanzen gemacht werden kann. Die Vergleichsfunktion "map" bildet die Attributwerte einer Instanz auf einen Wert ab, dessen Wertebereich durch einen der atomaren Datentypen "date", "real", "number" oder "varchar2" definiert ist. Da auf diesen Built-in-Datentypen bereits eine Ordnung vordefiniert ist, können die Werte problemlos miteinander verglichen und eine Ordnung auf den Instanzen definiert werden. Eine "map"-Funktion liefert also die relative Position einer Instanz innerhalb ihrer Objektklasse. Diese Funktion kann nicht überladen werden, da sie keine Parameter besitzen darf. Die Vergleichsfunktion "order" vergleicht zwei Instanzen eines Objekttyps miteinander. Aus diesem Grund hat die "order"-Funktion maximal zwei Parameter. Der erste Parameter ist der Built-in-Parameter "self". Als zweiter Parameter wird eine Instanz des gleichen Objekttyps verwendet. Ein Objekttyp darf nur eine "order"-Funktion besitzen, die somit nicht überladen werden kann. Der Rückgabewert einer "order"-Funktion ist immer ein numerischer Wert (z.B. –1, 0, 1), der das Ergebnis des Vergleichs repräsentiert. Innerhalb eines Objekttyps ist es nicht möglich, sowohl eine "map"- als auch eine "order"-Funktion zu definieren, deshalb muß eine Entscheidung getroffen werden, welche Vorgehensweise am besten für den jeweiligen Objekttypen geeignet ist. Wenn es darum geht eine große Anzahl von Instanzen untereinander zu vergleichen, ist die "map"-Funktion am besten geeignet, da durch einen Aufruf alle betroffenen Instanzen einen atomaren Wert zugewiesen bekommen, die dann sortiert werden. Die "order"-Funktion eignet sich nicht für eine große Anzahl von Instanzen, da sie immer nur zwei Instanzen auf einmal miteinander vergleichen kann und deshalb wiederholt aufgerufen werden muß, um alle betroffenen Instanzen miteinander zu vergleichen. 4.3.2 Kollektionstypen Ein Kollektionstyp (engl. collection type) ist eine Strukturbeschreibung, die zur Verwaltung einer Menge von geordneten Instanzen eines abstrakten Datentyps dient. Alle Instanzen eines Kollektionstyps sind immer vom gleichem Datentyp. Ein Kollektionstyp besitzt immer nur 53 Inhaltsverzeichnis ein Attribut, dessen Wertebereich entweder ein Built-in-Datentyp oder ein Objekttyp ist. Im Prinzip kann man einen Kollektionstyp als ein eindimensionales Array bezeichnen, der durch numerische Werte indiziert ist. Die Attribute eines Kollektionstyps können sowohl aus atomaren Built-in-Datentypen, als auch aus benutzerdefinierten Objekttypen bestehen. Ein Kollektionstyp kann als Wertebereich eines Attributs innerhalb eines Objekttyps eingesetzt oder aber in PL/SQL als Variable, Parameter oder Rückgabewert einer Funktion verwendet werden. Es existieren zwei unterschiedliche Arten von Kollektionstypen, "varrays" und vernestete Tabellen, die in den folgenden Abschnitten vorgestellt werden. Ein "varray" (variable size array) ist eine geordnete Menge von Instanzen, die alle durch den gleichen Datentyp spezifiziert sind und durch einen numerischen Index in ihrer Reihenfolge festgelegt sind. Es ist nicht gestattet "varray"s ineinander zu schachteln. Bei der Definition eines "varray"s wird angegeben, wie viele Instanzen maximal in dem "varray" gespeichert werden können. Ist eine Instanz erst einmal angelegt, so darf sie nicht mehr aus dem "varray" gelöscht werden. Die Speicherung der Instanzen eines "varray"s erfolgt intern innerhalb der Tabelle, in der sie als Wertebereich eingesetzt wird. Die Instanzen sind durch ihre Position im "varray" eindeutig gekennzeichnet und angeordnet. Das folgende Beispiel erzeugt einen "varray", in dem die Adressen des ersten bis dritten Wohnsitzes gespeichert werden können. CREATE TYPE ot_adresse AS OBJECT ( strasse VARCHAR2( 40 ), hausnr NUMBER( 5 ), plz NUMBER( 5 ), land VARCHAR( 20 ) ); CREATE TYPE var_wohnsitze AS VARRAY( 3 ) OF ot_adresse; Beispiel 4.3.1: Verwendung eines Objekttyps als "varray" Eine vernestete Tabelle ist eine ungeordnete Menge von Instanzen, die alle durch den gleichen Datentyp spezifiziert sind. Auch bei den vernesteten Tabellen ist es nicht gestattet, sie ineinander zu verschachteln. Durch den Index, der über die Instanzen einer vernesteten Tabelle gelegt wird, kann der Zugriff auf die Instanzen wie in einem Array vorgenommen werden. Die Anzahl von Instanzen, die eine vernestete Tabelle besitzen darf, ist nicht beschränkt. Es können dynamisch Instanzen eingefügt und auch gelöscht werden. Zu Anfang sind die Instanzen einer vernesteten Tabelle dicht organisiert. Durch die erlaubten Löschungen können Lücken entstehen, da zwar die Instanz an sich gelöscht wird, der Index aber bestehen bleibt. So bleibt die Eindeutigkeit des Index der Instanzen erhalten. Die Speicherung der Instanzen einer vernesteten Tabelle erfolgt in einer separaten Tabelle. Auf der separaten Tabelle der ist keine Ordnung definiert. Jedes Element hat zwar einen eindeutigen Index, der aber nichts mit der Anordnung der Elemente zu tun hat. Die folgende Tabelle verdeutlicht noch einmal, welche Unterschiede zwischen den beiden Kollektionstypen "varray" und vernesteter Tabelle bestehen. 54 Inhaltsverzeichnis Eigenschaften "varray" Vernestete Tabelle Anzahl der Instanzen Begrenzt Unbegrenzt Löschen von Instanzen Nicht erlaubt Erlaubt Anordnung der Instanzen Dicht (keine Lücken) Dicht und Licht (Lücken durch Löschungen) Speicherung der Daten Intern in der Tabelle (in-line) Extern in einer separaten Tabelle (out-of-line) Aufgabe des Index Eindeutige Kennzeichnung der Instanz, erstellt Ordnung. Eindeutige Kennzeichnung der Instanz Tabelle 4.3.1: Vergleich von Kollektionstypen 4.3.3 Objekttabellen Ein Objekttabelle (engl. object table) ist ein Spezialtyp einer Tabelle, da bei der Definition der Attribute nur Objekttypen verwendet werden dürfen oder aber die Objekttabelle aus einem einzigen Objekttypen besteht, wodurch die Attribute der Objekttabelle den Attributen des Objekttyps entsprechen. Objekttabellen dienen also dazu, Instanzen von Objekttypen anzulegen, sie zu speichern und zu verwalten. Jeder Instanz in einer Objekttabelle wird mit einem Objektidenfikator (OID) versehen, die sie eindeutig innerhalb der Tabelle identifiziert. Diese OID wird benötigt, um auf die Instanzen einer Objekttabelle zu referenzieren. Des weiteren ermöglicht es eine Objekttabelle, Sichten zu definieren, die gleichzeitig auf Instanzen relationaler und objektorientierter Konzepte basieren. 4.3.4 Referenzierte Spalten Der Datentyp "ref" definiert einen Wertebereich für Attribute, der nur einen Objektidentifikator des spezifizierten Types als gültigen Wert akzeptiert. Somit verbirgt sich hinter dem Datentyp "ref" ein objektwertiges Attribut, welches immer auf einen Instanz in einer Objekttabelle (siehe Abschnitt 4.3.3) verweist, da nur die Instanzen einer Objekttabelle einen Objektidentifikator besitzen. Der Einsatz von referenzierten Spalten muß gut überlegt sein, da zwar zum Zeitpunkt des Speicherns überprüft wird, ob die referenzierte Instanz existiert, aber beim Löschen einer Instanz in der Objekttabelle wird nicht überprüft, ob noch Referenzen auf diese existieren. So kann es zu Referenzen auf nicht mehr existente Instanzen kommen, die als hängende Referenzen (engl. dangling references) bezeichnet werden. Durch den Einsatz von benutzerdefinierten Triggern kann in den betroffenen Tabellen überprüft werden, ob eine Instanz noch referenziert wird oder ob sie gelöscht werden darf. 55 Inhaltsverzeichnis CREATE TYPE ot_adresse AS OBJECT ( strasse VARCHAR2( 40 ), hausnr NUMBER( 5 ), plz NUMBER( 5 ), land VARCHAR( 20 ) ); CREATE TABLE adresse OF ot_adresse; CREATE TABLE person ( name VARCHAR2( 30 ), vorname VARCHAR2( 30 ), geburtstag DATE, adresse REF adresse ); Beispiel 4.3.1: Verwendung von objekt-wertigen Attributen So kann es innerhalb dieses Beispiels zu der Situation kommen, daß die Adresse einer Person in der Objekttabelle "adresse" gelöscht wird, die Referenz in der Tabelle "person" weiterhin auf die gelöschte Instanz verweist. 4.3.5 Objektsichten Eine Objektsicht (engl. object view) ist eine virtuelle Tabelle, die ihre Instanzen aus den Attributwerten einer Anfrage an relationale und/oder objektorientierte Konzepte (Tabellen und Sichten) zusammenstellt. Durch die Definition von Instead-of-Triggern ist es möglich, wie auch bei rein relationalen Sichten, View-Updates zu steuern. Die Objektsicht dient als Schnittstelle für objektorientierte Entwicklungstools, um relationale Daten als Einheit zu repräsentieren und auf sie zugreifen zu können. Wie bei den Objekttabellen wird auch bei den Objektsichten eine OID benötigt, damit Referenzen auf die Instanzen ermöglicht werden. Um zu gewährleisten, daß diese OID immer eindeutig ist, wird einer der selektierten Attributwerte als OID der Objektsicht deklariert. CREATE TABLE person ( id NUMBER (5), name VARCHAR2 (20), vorname VARCHAR2 (20), wohnort VARCHAR2 (20) ); 56 Inhaltsverzeichnis CREATE TYPE ot_person AS OBJECT ( id NUMBER (5), name VARCHAR2 (20), vorname VARCHAR2 (20) ); CREATE VIEW einwohner_von_bonn OF ot_person WITH OBJECT OID ( id ) AS SELECT p.id, p.name, p.vorname FROM person p WHERE wohnort = 'Bonn'; Beispiel 4.3.1: Definition einer Objektsicht In diesem Beispiel wird eine Objektsicht generiert, deren Struktur durch den Objekttyp "ot_person" festgelegt ist. Die Tupel dieser Sicht werden aus den Tupeln der Tabelle "person" aufgebaut, deren Attribut "wohnort" den Wert "Bonn" besitzt. Die OID der Instanzen der Objekttabelle wird durch den Wert "id" aus der Tabelle "person" initialisiert. 4.4 SQL-92-Standard-Erweiterungen von Oracle8 Die Sprache SQL (structured query language) ist entwickelt worden, um Anfragen an relationale Datenbanken zu stellen und auszuwerten. Da es mittlerweile eine Vielzahl von relationalen Datenbanksystemen gibt, ist die Anfragesprache genormt worden, um die Syntax von Standardoperationen festzulegen und dadurch die Benutzung der unterschiedlichen Systeme zu vereinfachen. Die zur Zeit aktuelle Norm von SQL ist der SQL-92-Standard, der auch als SQL-2-Standard bezeichnet wird. Die Konzepte von Oracle orientieren sich im wesentlichen am SQL-92-Standard, bieten aber Erweiterungen, da sie zusätzliche Konzepte wie zum Beispiel Objekttypen unterstützen, die im SQL-92-Standard nicht vorgesehen sind. Dieser Abschnitt beschreibt die vom SQL-92-Standard abweichenden Eigenschaften von Oracle8. 4.4.1 Zusätzliche Datentypen unter Oracle8 Die folgenden Datentypen sind Built-in-Datentypen (siehe Abschnitt 4.2.1), die von Oracle8 zur Verfügung gestellt werden und nicht Bestandteil des SQL-92-Standards sind, bzw. einem anderen Standard-SQL-Datentyp entsprechen. Oracle8 SQL-92 number(x,y) numeric(x,y) varchar(x), varchar2(x) character varying(x) 57 Inhaltsverzeichnis Oracle8 SQL-92 long --- raw --- long raw --- rowid --- blob --- clob --- nclob --- bfile --Tabelle 4.4.1: Zusätzliche Built-in-Datentypen von Oracle8 Zusätzlich zu diesen Built-in-Datentypen ist es in Oracle8 möglich die benutzerdefinierten Objekttypen (siehe Abschnitt 4.3.1), referenzierte Spalten (siehe Abschnitt 4.3.4), und Kollektionstypen (siehe Abschnitt 4.3.2) zu erstellen und zu benutzen, die im SQL-92-Standard nicht vorgesehen sind. Weitere Informationen zum Thema Datentypen sind in der Oracle8Online-Hilfe zu finden ([Ora98]). 4.4.2 Erweiterte und neue Funktionen in Oracle8 Die einzigen Funktionen die laut SQL-92-Standard zur Verfügung stehen, sind die internen Built-in-Funktionen "avg", "count", "max", "min" und "sum". Unter Oracle ist es möglich maximal zwei unterschiedliche Funktionen ineinander zu verschachteln, was laut SQL-92-Standard nicht zulässig ist. Des weiteren stellt Oracle zusätzlich eine Vielzahl von weiteren numerischen Funktionen, Funktionen zur Manipulation und Analyse von Zeichenketten und Datumsfunktionen zur Verfügung, deren Beschreibung an dieser Stelle zu weit führen würde und zum Beispiel in der Oracle8-Online-Hilfe nachgelesen werden kann. Zusätzlich zu den Built-in-Funktionen von Oracle8, besteht auch noch die Möglichkeit interne benutzerdefinierte Funktionen und Prozeduren zu definieren und sie in Paketen zusammengefaßt als Bestandteil eines Datenbankschemas zu speichern. 4.4.3 Pseudospalten Hinter dem Begriff der Pseudospalten verbergen sich Funktionen, die in DML-Operationen wie Attribute einer Tabelle angesprochen werden können, deren Werte aber nicht innerhalb einer Tabelle gespeichert sind. Der Wert einer Pseudospalte kann durch eine Anfrage an die Datenbasis selektiert, aber nicht durch die Standardoperationen "insert", "update" und 58 Inhaltsverzeichnis "delete" verändert werden. Auf zwei dieser Funktionen wird im folgenden genauer eingegangen, da sie im Rahmen dieser Diplomarbeit benutzt werden. Die beiden Funktionen "currval" und "nextval" werden dazu benutzt, den Wert einer "sequence" zu extrahieren und manipulieren. Eine "sequence" ist ein Schemaelement, welches zur Generierung von eindeutigen und fortlaufenden Werten eingesetzt wird. Diese Werte können benutzt werden, um eindeutige Werte für Primärschlüssel zu erzeugen. Die Funktion "currval" liefert den aktuellen Wert einer Sequenz. Durch die Funktion "nextval" wird der numerische Wert der Sequenz durch die Addition eines numerischen Wertes, der bei der Definition einer Sequenz festgelegt wird, modifiziert und der neue aktuelle Wert zurückgeliefert. Diese beiden Funktionen können innerhalb der Attributliste einer "select"-Operation verwendet werden, wenn dieser nicht Bestandteil einer Unteranfrage ist oder zur Definition einer Sicht verwendet wird. Des weiteren können sie als Attributwerte in einer "insert" oder "update"-Operation verwendet werden. 4.4.4 Zusätzliche Operatoren Die folgenden zusätzlichen Operatoren werden von Oracle8 unterstützt, obwohl sie nicht Bestandteil des SQL-92-Standards sind. Operator || !=, ^=, ¬= Funktion Konkatenation von Zeichenketten Vergleichsoperatoren auf Ungleichheit intersect Mengenoperator, der zwei Anfragen miteinander verbindet und der alle Datensätze liefert, die sowohl Ergebnis der zweiten als auch der ersten Anfrage sind. minus Mengenoperator, der zwei Anfragen miteinander verbindet und der alle Datensätze der ersten Anfrage liefert, die nicht auch Datensätze der zweiten Anfrage sind. Tabelle 4.4.1: Zusätzliche Operatoren von Oracle8 4.4.5 Zusätzliche Konzepte Die Syntax einiger Operationen des SQL-92-Standards, ist unter Oracle8 erweitert worden und neue Operationen sind dazugekommen. Dies ist durch die Einführung von neuen Konzepten motiviert worden. In der folgenden Tabelle wird ein Überblick über die Oracle8Konzepte gegeben, die im SQL-92-Standard nicht enthalten sind. 59 Inhaltsverzeichnis KONZEPTE CLUSTER ALTER CREATE DROP X X X CONTROLFILE DATABASE X X X DATABASE LINK X X DIRECTORY X X FUNCTION X X X INDEX X X X X X X X LIBRARY PACKAGE X PACKAGE BODY X PROCEDURE X X X PROFILE X X X RESOURCE COST X ROLLBACK SEGMENT X X X ROLE X X X SEQUENCE X X X SESSION X SNAPSHOT X X X SNAPSHOT LOG X X X X X SYNONYM SYSTEM X TABLE X X X TABLESPACE X X X TRIGGER X X TYPE X X X X X TYPE BODY USER X X VIEW X X Tabelle 4.4.1: Erweiterte und neue Konzepte von Oracle8 60 Inhaltsverzeichnis Die DDL- und DML-Operationen von Oracle8 sind in ihrer Funktion erweitert worden, damit sie auch auf diese neuen Konzepte angewendet werden können. Auf die genaue Syntax der erweiternden Klauseln und Parametern wird an dieser Stelle nicht eingegangen, da dies den Rahmen dieses Abschnitts sprengen würde. Weitere Informationen zu diesen Konzepten und ihren Einsatzgebieten, sind in der Oracle8-Online-Hilfe im Abschnitt „SQL-Reference“ zu finden. 61 Inhaltsverzeichnis Andrea Scheuber und Michael Horn 5 Eine Oracle-basierte Implementierung des Chimera Prototyping Tool Dieses und die folgenden Kapitel gehen auf die Architektur des Chimera Prototyping Tools für Oracle und auf die unterschiedlichen Aspekte der Übersetzung von Kommandos der Datendefinitionssprache (DDL) und der Datenmanipulationssprache (DML) von Chimera ein. Eine kurze Anmerkung zum Sprachgebrauch in den folgenden Kapiteln: Bisher gab es nur eine Implementierung des Chimera Prototyping Tools (CPT) basierend auf Phoenix. Im Rahmen dieser beiden Diplomarbeiten ist eine zweite Implementation entstanden, die ebenfalls Chimera Prototyping Tool heißt. Im folgenden wird deshalb die auf Phoenix basierende Implementierung mit CPTPhx und die neue Implementierung mit CPTOracle bezeichnet. 5.1 Architektur des CPTOracle Die neue Implementation des Chimera Prototyping Tools basiert sehr stark auf der bisherigen Implementation. Der Chimera-Compiler wurde um drei Komponenten erweitert: Jeweils eine Komponente übernimmt die Übersetzung eines Chimera-Schemas in ein Oracle-SQL-Schema (siehe Kapitel 6) und eine Komponente übersetzt die Datenmanipulationssprache von Chimera nach SQL (siehe Kapitel 8). Beide Komponenten benötigen die Komponente zur Übersetzung deklarativer Ausdrücke (siehe Kapitel 7). Der Phoenix-DBPL-Interpretierer der bestehenden Implementation ist durch das ECLiPSe-Oracle-Interface von Thomas Kolbe (siehe Abschnitt 5.2 und [Kol95]) ersetzt worden. Abschließend wurde das Phoenix-System durch einen Oracle-Datenbankserver ersetzt. Der Oracle-Datenbankserver übernimmt im Rahmen des CPTOracle noch eine weitere, wichtige Aufgabe: Sämtliche Typüberprüfungen werden durch den Server durchgeführt. Durch dieses Vorgehen mußte keinerlei Typüberprüfung innerhalb des CPTOracle implementiert werden. 62 Inhaltsverzeichnis DDL DML CPT/CI CPT/GUI Chimera Compiler load_schema chimera_closedb chimera_createdb chimera_destroydb chimera_opendb dml CDD InfoDB1 ECLiPSe-Oracle-Interface CPTOracle DB Oracle8 DBMS InfoDB2 Abbildung 5.1: Architektur des Chimera Prototyping Tools für Oracle (CPTOracle) 63 Inhaltsverzeichnis Die auffälligsten Unterschiede zwischen den Architekturen der beiden Implementationen sind die zwei zusätzlichen Datenbanken InfoDB1 und InfoDB2. Erläuterungen des Aussehens und der Funktionen der einzelnen Komponenten werden in den entsprechenden Kapiteln gegeben. Die beiden zusätzlichen Datenbanken werden für folgende Aufgaben benötigt: • Speicherung zusätzlicher Informationen für die Implementierungen von Schemaobjekten (siehe Kapitel 6) • Speicherung temporärer Daten, die bei der Übersetzung deklarativer Ausdrükke anfallen (siehe Kapitel 7) • Informationen für die Transaktionsverwaltung (siehe Kapitel 8) Ebenso wie das CPTPhx, wird die Konfiguration des CPTOracle durch die Konfigurationsdatei ".chimerarc" festgelegt. Die neue Implementierung benötigt folgende Parameter: • CPT-Verzeichnis • Datenverzeichnis • Oracle Benutzerkennung • Oracle Paßwort • Oracle Service ID (SID) Die Konfiguration des CPT- und Datenverzeichnisses ist aus dem CPTPhx übernommen worden. Die weiteren Information beziehen sich auf den Oracle-Datenbankserver. In der Datei muß sowohl der Benutzerkennung als auch das Oracle Paßwort eingegeben werden. CPTOracle meldet sich automatisch unter Verwendung der Benutzerkennung und des Paßwortes am Server an. Die Oracle Service ID (SID) wird momentan nicht benötigt, da die verwendete ECLiPSe-Oracle-Schnittstelle diese nicht unterstützt. Andere Schnittstellen wie z.B. die Oracle Schnittstelle SQL+ benötigen allerdings diese Information für eine korrekte Anmeldung am Datenbankserver. Beide Implementierung von Chimera sind nicht kommerzielle Systeme. Daher ist das Sicherheitsmanko einer unverschlüsselten Speicherung der Benutzerkennung und des dazugehörigen Paßwortes zu verschmerzen. Durch dieses Vorgehen ist eine Verwendung der graphischen Oberfläche des CPT sichergestellt, ohne das daran Veränderungen vorgenommen werden mußten. Zusätzlich zu den neuen Komponenten und Datenbanken mußten die Aufgaben der sechs Hauptfunktionen des Chimera Prototyping Tools teilweise verändert oder neu definiert werden. Die Funktionen werden im folgenden durch die entsprechenden Prolog-Prädikate repräsentiert: • load_schema/1 • chimera_createdb/1 64 Inhaltsverzeichnis • chimera_opendb/1 • chimera_closedb/0 • chimera_destroydb/0 • dml/0 und dml/1 Die Schnittstelle für die Datenmanipulation (dml/0 und dml/1) des CPT mußte nur geringfügig verändert werden. Die beiden Prädikate unterscheiden sich nur dadurch, daß das erste Prädikat (dml/0) einen interaktiven Datenmanipulationsmodus aktiviert, während das zweite Prädikat (dml/1) eine Stapelverarbeitung für ein Skript mit mehreren Befehlen aktiviert. Jede Transaktion wird an das Modul zur Übersetzung imperativer Ausdrücke weitergeleitet (siehe Kapitel 8). 5.1.1 Einlesen eines Chimera-Schemas (load_schema/1) Das Prolog-Prädikat "load_ schema/1" lädt eine Schemadatei und übersetzt den Inhalt der Datei in die interne Darstellung des Chimera Data Dictionary (CDD). Zusätzlich zur bestehenden Funktionalität des CPTPhx muß dieses Prädikat noch weitere Aufgaben übernehmen. Die interne Darstellung des CDD kann aufgrund der Implementierung der Übersetzung deklarativer Ausdrücke nicht für die Übersetzung der Implementationen der verwendeten Schemaobjekte eingesetzt werden. Die Implementation der abgeleiteten Objektklasse "abitur" aus Kapitel 2 define implementation for abitur population abitur(X) <oberstufe(X), X.klasse = 13, X.durchschnitt <= 4 end; wird durch das Prädikat "load_schema/1" in folgende interne Darstellung übersetzt: ... ******************************************** *** population_rule ******************************************** (21,user): abitur, ctvc(abitur, [var(X)]), [ctvc(oberstufe, [var(X)]), comp(identity, dot(var(X), klasse), const(13, integer)), comp(less_equal, dot(var(X), durchschnitt), const(4, integer))] ... Obiger Eintrag des CDD entspricht dem Ergebnis der Syntaxüberprüfung durch den ChimeraParser. Jede Regel wird im CDD durch ein 3-Tupel repräsentiert: Name der Klasse, linke Seite der Regel (Kopf der Regel) und rechte Seite der Regel (Rumpf der Regel).Der Rumpf 65 Inhaltsverzeichnis der Regel besteht aus einer Liste, die das Ergebnis der Syntax- und Typanalyse des deklarativen Ausdrucks repräsentiert. Die in Kapitel 7 vorgestellte Übersetzung deklarativer Ausdrükke benötigt für die Übersetzung eine Liste von Zeichenketten. Die obige Repräsentation des Rumpfes der Regel entspricht daher nicht dem erforderlichen Format. Während des Lesevorgangs eines Chimera-Schemas wird deshalb eine zusätzliche Version der im Schema verwendeten Regeln in der "InfoDB1" abgespeichert. Das Prädikat "implementation/3" speichert die benötigten Zeichenketten. Es benötigt folgende drei Parameter: • Name der zur Implementation gehörenden Klasse • Art des implementierten Schemaobjektes • Definition der Regel in Form einer Liste von Zeichenketten Durch das Design des Prädikates können alle möglichen Implementationen für abgeleitete Klassen und Attribute, Sichten, Integritätsbedingungen und Trigger abgespeichert werden. Die Implementation der abgeleiteten Objektklasse "abitur" wird wie folgt durch das Prolog-Prädikat abgespeichert: implementation( abitur, population, [abitur, "(", var(X), ")", <-, oberstufe, "(", var(X), ")", ",", var(X), ., klasse, =, 13, ",", var(...), ...]) Aus dem Fakt der Prolog-Datenbank können anschließend alle benötigten Informationen ausgelesen werden. Obiges Fakt repräsentiert die Implementation der Klasse "abitur". Es wird die "population" für die abgeleitete Klasse definiert. Das dritte Attribut entspricht der Definition der Populationsregel. 5.1.2 Anlegen einer Chimera-Datenbank (chimera_createdb/1) Das Prolog-Prädikat "chimera_createdb/1" startet die Übersetzung eines ChimeraSchemas in ein Oracle8-SQL-Schema und erzeugt eine auf dem SQL-Schema basierende Oracle8-Datenbank. Als Parameter benötigt dieses Prädikat den Namen der zu erzeugenden Datenbank. Das weitere Vorgehen entspricht dem des bestehenden CPTPhx. Im Datenverzeichnis des CPT wird ein Unterverzeichnis angelegt, in dem alle zur Datenbank gehörenden Informationen gespeichert werden. Folgende Dateien werden automatisch erzeugt: • Datei für die Informationen des CDD (Dateiname: dbname.cdd) • Skript der Schemaübersetzung (Dateiname: dbname.sql) Das komplette CDD wird ausgelesen und in einer Datei gespeichert. Jeder Eintrag wird durch eine Liste repräsentiert. Die Liste umfaßt drei Werte: das Chimera-Modul, den Konzeptname und die Konzeptdefinition. Die Konzeptdefinition entspricht einer Liste von Zeichenketten. Das CDD-Beispiel aus Kapitel 3 wird wie folgt bei der Erzeugung der Datenbank gesichert: 66 Inhaltsverzeichnis [chimera, module, [chimera]]. [chimera, module, [user]]. [user, object_class, [adresse, [extensional]]]. [user, object_class, [person, [extensional]]]. [user, object_class, [schueler, [extensional]]]. [user, object_class, [oberstufe, [extensional]]]. [user, object_class, [abitur, [derived]]]. [user, value_class, [geschlecht, string]]. [user, superclass, [person, schueler]]. [user, superclass, [schueler, oberstufe]]. [user, superclass, [oberstufe, abitur]]. ... [user, population_rule, [abitur, ctvc(abitur, [var(X)]), [ctvc(oberstufe, [var(X)]), comp(identity, dot(var(X), klasse), const(13, integer)), comp(less_equal, dot(var(X), durchschnitt), const(4, integer))]]]. Die zweite Datei enthält das Ergebnis der im Kapitel 6 vorgestellten Schemaübersetzung eines Chimera-Schemas in ein Oracle8-SQL-Schema. Das resultierende SQL-Skript kann zur Erzeugung der Datenbank mit Hilfe einer beliebigen Oracle-Schnittstelle (z.B. SQL+)eingespielt werden. Das genaue Aussehen der Datei wird durch die Beispiele in Kapitel 6 erläutert. 5.1.3 Öffnen einer Chimera-Datenbank (chimera_opendb/1) Das Prädikat "chimera_opendb/1" öffnet eine bestehende Datenbank für die Benutzung durch das CPTOracle. Hierbei wird der Inhalt der CDD-Datei zurück in das CDD geschrieben. Nachdem die Datei komplett gelesen wurde, ist das CPTOracle bereit, weitere Aufgaben zu erfüllen. Die momentane Implementation des CPTOracle überprüft nicht, ob die Tabellen, Sichten, Integritätsbedingungen und Trigger den Information des CDD entsprechen. Eine Überprüfung auf Korrektheit der bestehenden Datenbank ist selbst mit sehr großem Aufwand nicht möglich. Oracle-SQL bietet nur die Möglichkeit, das Vorhandensein einer Tabelle zu überprüfen, die genaue Definition der Tabelle läßt sich nicht überprüfen. In SQL existieren keinerlei Mechanismen die Definition von Integritätsbedingungen, Triggern und Sichten mit einer Schemadefinition zu überprüfen. Die einzige, umständliche Möglichkeit Integritätsbedingungen, Trigger und Sichten zu überprüfen wäre das Löschen der bestehenden und eine erneute Übersetzung der Informationen des CDD. Ein Abgleich der Informationen des geladenen CDD und der bestehenden Datenbank ist demnach nicht effizient möglich. 5.1.4 Schließen einer Chimera-Datenbank (chimera_closedb/0) Durch das Schließen einer Chimera-Datenbank werden alle internen Informationen bzgl. der Datenbank gelöscht. Alle Einträge im CDD und der internen Datenbank "infoDB1" werden entfernt. Obwohl die bisherige Implementierung des CPTOracle noch keine Schemaevolution 67 Inhaltsverzeichnis unterstützt, werden die Informationen des CDD vor dem Löschen noch einmal ausgelesen und in der entsprechenden Datei gespeichert. Das CPT führt keinerlei Datenbankbefehle beim Schließen einer Chimera Datenbank durch. Die bedeutet, daß eventuelle Daten, die noch nicht mit einem "commit" bestätigt wurden, verloren gehen. Der Benutzer ist in diesem Falle selbst verantwortlich, ob die gemachten Änderungen im Datenbestand erhalten bleiben sollen oder nicht. Die Abmeldung des CPTOracle am Oracle-Server geschieht ebenfalls erst nach Beendigung der Applikation. Es ist momentan nicht vorgesehen, die Verbindung zu Server während einer Sitzung zu verändern oder zu verlassen. Das Programm meldet sich automatisch während des Beendens am Datenbankserver ab. 5.1.5 Löschen einer Chimera-Datenbank (chimera_destroydb/0) Nur eine geöffnete Chimera-Datenbank kann gelöscht werden. Der Löschvorgang basiert auf den gespeicherten Informationen des CDD. Zuerst werden alle ChimeraIntegritätsbedingungen, -Trigger und -Sichten gelöscht. Anschließend werden alle OracleTabellen, -Trigger und -Sichten gelöscht, die eine Chimera-Klassenhierarchie repräsentieren. Elemente einer Oracle-Datenbank können mit Hilfe der SQL-Operation "drop" gelöscht werden. Die "drop"-Operation erwartet folgende zwei Parameter: • Schemakonzept • Name des Konzeptes Folgende Beispiele löschen z.B. einen Oracle-Trigger namens "abitur_bestanden" und eine Oracle-Sicht namens "abitur": drop trigger abitur_bestanden; drop view abitur; Nachdem alle Tabellen, Integritätsbedingungen usw. gelöscht wurden, werden alle Dateien und Verzeichnisse zur bestehenden Datenbank gelöscht. Abschließend werden alle Informationen aus den internen Prolog-Datenbanken gelöscht. 5.2 Das ECLiPSe-Oracle-Interface Dieses Kapitel stellt das ECLiPSe-Oracle-Interface vor, das zur Anbindung des CPTOracle an eine Oracle-Datenbank benutzt wird. Der Inhalt basiert hauptsächlich auf der Dokumentation "Anbindung des RDBMS Oracle an ECLiPSe" von Thomas Kolbe [Kol95]. Das ECLiPSeOracle-Interface stellt mehrere Prädikate zur Verfügung, die einen Verbindungsaufbau und die Kommunikation zwischen dem Prolog-System ECLiPSe und einem Datenbanksystem von Oracle ermöglichen. Diese Schnittstelle wird benutzt, um aus ECLiPSe sowohl DDL- als auch 68 Inhaltsverzeichnis DML-Operationen an das Datenbanksystem zu schicken. Die wichtigsten Prädikate dieser Schnittstelle werden im folgenden vorgestellt. Das Prädikat "sql_login" ist für den Aufbau der Verbindung zwischen ECLiPSe und der Datenbank zuständig. Es benötigt dazu zwei Parameter, nämlich den Namen eines Datenbankbenutzers und das dazugehörige Paßwort, die als Prolog-Atom oder Prolog-String sein müssen. Durch das Setzen der Umgebungsvariablen ORACLE_SID wird festgelegt, an welche Datenbank sich der Verbindungsaufbau richten soll. Das Prädikat "sql_logout" beendet die Verbindung zwischen ECLiPSe und Datenbanksystem. Falls Änderungen am Datenbestand noch nicht durch den Befehl "commit" bestätigt worden sind, wird dies vor dem Auflösen der Verbindung noch nachgeholt. Das Prädikat "sql_commit" wird benutzt, um eine Transaktion abzuschließen und die vorgenommenen Änderungen in der Datenbank permanent verfügbar zu machen, indem es den Befehl "commit" an die Datenbank schickt. Das Prädikat "sql_rollback" setzt sämtliche Änderungen einer Transaktion, die noch nicht mit dem Befehl "commit" abgeschlossen worden ist zurück, indem es den Befehl "rollback" an die Datenbank schickt. Die Prädikate "sql_insert" und "sql_delete" dienen dazu, die SQL-DMLOperationen "insert" und "delete" an eine Oracle-Datenbank zu richten und auszuführen. Das Prädikat "sql_insert" benötigt drei Parameter, um eine syntaktisch korrekte "insert"-Operation an eine Oracle-Datenbank zu schicken. Der erste Parameter enthält den Tabellennamen, der einen gültigen Tabellennamen der Oracle-Datenbank als Wert besitzen und als Prolog-String oder Prolog-Atom vorliegen muß. Der zweite Parameter ist eine Attributliste, die alle Namen der Attribute beinhaltet, denen durch die "insert"-Operation ein Wert zugewiesen wird. Der zweite Parameter besteht aus einer Werteliste, die genauso lang sein muß, wie die Liste der Attributnamen, da sie die dazugehörigen Attributwerte beinhaltet. Prädikat sql_insert('person', ['Name','Vorname','P_Alter'], ['Scheuber','Andrea', 26 ]) SQL-Operation INSERT INTO person ( Name, Vorname, P_Alter ) VALUES('Scheuber',Andrea',26); Beispiel 5.2.1: Verwendung des Prolog-Prädikats "sql_insert" In dem Beispiel 5.2.1 werden die Parameter des Prolog-Prädikats "sql_insert" in eine SQL-Insert-Operation umgesetzt. Dabei legt der erste Parameter "person" fest, daß die "insert"-Operation an die Relation "person" gerichtet wird. Durch die Liste der Attributnamen "Name", "Vorname" und "p_Alter" wird bestimmt, welche Attribute der Relation einen Attributwert zugewiesen bekommen. Die Liste der Attributwerte beinhaltet die Werte, die den Attributen zugewiesen werden. Durch die Reihenfolge der Attributnamen und –werte ist automatisch festgelegt, daß das Attribut "Name" den Wert 'Scheuber', das Attribut "Vorname" den Wert 'Andrea' und das Attribut "p_Alter" den Wert 26 zugewiesen bekommt. 69 Inhaltsverzeichnis Das Prädikat "sql_delete" benötigt fünf Parameter, um eine syntaktische korrekte "delete"-Operation an eine Oracle-Datenbank zu schicken. Der erste Parameter beinhaltet, wie auch bei dem Prädikat "sql_insert", einen gültigen Tabellennamen. Der zweite Parameter ist ein String, der eine "where"-Bedingung formuliert, aber nicht selbst das Schlüsselwort "where" beinhaltet. Handelt es sich bei diesem Parameter um einen Leerstring, so wird keine "where"-Bedingung erzeugt, wenn es sich bei dem dritten und vierten Parameter, um leere Listen handelt. Bei diesen beiden Parametern handelt es sich wieder, um Listen, die Attributnamen und Attributwerte beinhalten. Sind diese beiden Listen nicht leer, so wird eine "where"-Bedingung aus ihnen formuliert, die zur Folge hat, daß nur Datensätze aus der festgelegten Tabelle gelöscht werden, deren Attribute aus der Attributliste als Wert die dazugehörigen aufgelisteten Werte beinhalten. Der fünfte und letzte Parameter ist ein Rückgabeparameter, der die Anzahl der gelöschten Datensätze in der Oracle-Datenbank zurück liefert. Prädikat SQL-Operation sql_delete ( 'person', 'p_alter < 30' ['Name'],['Scheuber'], Rows ). DELETE FROM WHERE AND Rows = 1 1 Row(s) affected person p_alter < 30 Name = 'Scheuber'; Beispiel 5.2.2: Verwendung des Prolog-Prädikats "sql_delete" Das Beispiel 5.2.2 zeigt, wie aus den Parametern des Prolog-Prädikats "sql_delete" eine SQL-Delete-Operation aufgebaut wird. Der erste Parameter 'person' legt fest, daß die "delete"-Operation an die Relation "person" gerichtet wird. Der zweite Parameter wird als "where"-Klausel in die "delete"-Operation übernommen. An diese "where"Klausel wird die zusätzliche Bedingung, die sich aus den Listen mit dem Attributnamen und – wert ergeben angehängt. Das Prädikat "sql_exec" wird dazu benutzt, um eine beliebige SQL-Operation zu formulieren, die an eine Oracle-Datenbank geschickt wird. Da keine speziellen Prädikate existieren, um DDL-Operationen auszuführen, ist dies die bisher einzige Möglichkeit via ECLiPSeTabellen und andere Elemente einer Schemadefinition in einer Oracle-Datenbank anzulegen. Des weiteren ist es auch die einzige Möglichkeit, eine Update-Operation zu formulieren und an eine Datenbank zu schicken, da für diese Operation auch kein spezielles Prädikat existiert. Das Prädikat "sql_exec" benötigt vier Parameter, von denen der erste Parameter eine beliebige SQL-Operation beinhalten kann. Bei der Formulierung der SQL-Operation sollte folgendes beachtet werden: Da Werte in Form von Zeichenketten innerhalb einer SQL-Operation durch einfache Hochkommata eingeschlossen werden müssen, empfiehlt es sich die gesamte SQL-Operation als Prolog-String in doppelten Hochkommata zu formulieren, da innerhalb eines Prolog-Strings einfache Hochkommata ohne Probleme verwendet werden können. Dies ist bei der Definition der SQL-Operation als Prolog-Atom nicht der Fall, da ein Prolog-Atom durch einfache Hochkommata eingeschlossen wird, und deshalb innerhalb des Atoms keine einfachen Hochkommata verwendet werden dürfen. Die drei weitere Parameter des Prädikats 70 Inhaltsverzeichnis "sql_exec" sind Rückgabeparameter, die bei Auftreten eines Fehlers den entsprechenden Oracle-Fehlercode und den dazugehörigen Fehlertext oder bei fehlerfreier Ausführung der Operation die Anzahl der bearbeiteten Datensätze zurückliefern. Prädikat SQL-Operation sql_exec( CREATE TABLE person "CREATE TABLE person ( name VARCHAR( 30 ), ( Name VARCHAR( 30 ), vorname VARCHAR( 30 ), Vorname VARCHAR( 30 ), p_alter NUMBER( 3 ) P_Alter NUMBER( 3 ) )", ); ReturnCode, ReturnMsg, Rows). ReturnCode = 0 ReturnMsg = "" Rows = 0 Beispiel 5.2.3: Verwendung des Prolog-Prädikats "sql_exec" Das Beispiel 5.2.3 zeigt die Umsetzung einer DDL-Operation, die zur Erstellung einer Relation dient. Der erste Parameter beinhaltet die gesamte DDL-Operation, die ohne Veränderungen an die Oracle-Datenbank weitergeleitet wird. Da diese Operation durchgeführt werden konnte, sind die Rückgabeparameter "ReturnCode" und "ReturnMsg" mit der Zahl 0, bzw. mit einem Leerstring unifiziert worden, da kein Fehler aufgetreten ist und somit auch kein Fehlercode und somit auch keine Fehlermeldung existiert. Da auch keine Datensätze durch eine DDL-Operation beeinflußt werden, wird die Variable "Rows" mit der Zahl 0 unifiziert. Die folgenden Prädikate werden dazu benutzt, selektierte Tupel aus den Relationen einer Oracle-Datenbank mit einer Variablenliste zu unifizieren und innerhalb eines PrologPrädikats weiter zu verwenden. Bei der Verwendung dieser Prädikate muß auf folgendes geachtet werden: Jedes der folgenden Prädikate legt einen Cursor in der Oracle-Datenbank an, der zur Selektion von Tupelmengen benutzt wird. Ein Cursor ist eine Datenstruktur vom Typ "record". Die Attribute eines Cursors bekommen durch eine "select"-Operation die entsprechenden Werte zugewiesen. Da die Anzahl der gleichzeitig geöffneten Cursor in einem Oracle-Datenbanksystem per Default auf 10 beschränkt ist, muß entweder der Wert des entsprechenden Systemparameters verändert werden oder es muß immer erst die Selektion einer Tupelmenge abgeschlossen und der verwendete Cursor geschlossen sein, bevor ein weiteres selektierendes Prädikat benutzt wird. Auf diese Weise ist immer nur maximal ein Cursor geöffnet. Das Prädikat "sql_query" wird verwendet, um eine "select"-Operation zu konstruieren, die einen oder mehrere Tupel aus einer oder mehreren Relationen selektiert. Dieses Prolog-Prädikat benötigt fünf Parameter. Der erste Parameter besteht aus einer Liste von Attributnamen, die alle Attribute beinhaltet, deren Werte selektiert werden sollen. Der zweite Parameter ist entweder ein Prolog-String oder Prolog-Atom, der die Namen der Relationen 71 Inhaltsverzeichnis beinhaltet, aus denen die Daten selektiert werden sollen. Die einzelnen Relationsnamen werden durch ein Komma voneinander getrennt. Der dritte Parameter beinhaltet die "where"Klausel der "select"-Operation in Form eines Prolog-Strings oder –Atoms, die nicht das Schlüsselwort "where" beinhaltet. Der vierte Parameter dient dazu, beliebige SQLKlauseln, wie zum Beispiel "order by", hinter der "where"-Klausel der "select"Operation anzuhängen. Der fünfte Parameter ist eine Liste von Variablen, die genau so viele Variablen besitzen muß, wie die Attributliste des ersten Parameters, da die selektierten Attributwerte mit den Variablen aus der Variablenliste unifiziert werden. Dies geschieht solange, wie eine neue passende Variablenbelegung gefunden wird. Sind alle Variablenbelegungen gefunden worden, so schlägt das Prädikat fehl. Prolog-Prädikat SQL-Operation sql_query( ['Name','Vorname','p_Alter'], 'Person', "Name = 'Scheuber'", "ORDER BY p_alter", [Name, Vorname, Alter] ). SELECT FROM WHERE ORDER BY Name,Vorname,p_Alter person Name = 'Scheuber' p_Alter; Name = 'Scheuber' Vorname = 'Margret' Alter = 56 More?(;) Name Scheuber Scheuber Vorname Margret Berthold p_Alter 56 60 Name = 'Scheuber' Vorname = 'Berthold' Alter = 60 More?(;) no (more) solution. Beispiel 5.2.4: Verwendung des Prolog-Prädikats "sql_query" In dem Beispiel 5.2.4 wird die Konstruktion einer SQL-Select-Operation durch das PrologPrädikat "sql_query" beschrieben. Der erste Parameter des Prädikats besteht aus einer Liste, welche die Attribute "Name", "Vorname" und "p_Alter" beinhaltet. Die Werte dieser Attribute sollen aus der Relation "person" selektiert werden, die durch den zweiten Parameter des Prädikats festgelegt wird. Der dritte Parameter des Prädikats beinhaltet die "where"-Klausel, durch welche die Anzahl der zu selektierenden Datensätze der Relation "person" auf diejenigen beschränkt wird, deren Attribut "name" als Wert die Zeichenkette 'Scheuber' besitzt. Als zusätzliche Klausel wird in diesem Beispiel die "order by"-Klausel verwendet, durch welche die Reihenfolge, in der die Tupel selektiert werden, beeinflußt wird. Die "order by"-Klausel wird über das Attribut "p_Alter" definiert, was zur Folge hat, daß die Tupel in der Reihenfolge des aufsteigenden Alters sortiert werden. Das Prädikat "sql_querydistinct" unterscheidet sich von dem Prädikat "sql_query" nur durch die zusätzliche Verwendung des Schlüsselworts "distinct" 72 Inhaltsverzeichnis bei der Konstruktion der SQL-Select-Operation. Dieses Schlüsselwort hat zur Folge, daß keine Tupel mehrfach selektiert werden, deren Attributwerte alle identisch sind. Prolog-Prädikat SQL-Operation sql_querydistinct ( ['Name'], 'Person', "", "ORDER BY Name", [Name] ). SELECT FROM ORDER BY Name = 'Horn' More?(;) Name = 'Scheuber' More?(;) Name Horn Scheuber Schmitz Name = 'Schmitz' More?(;) DISTINCT( Name ) Person Name; no (more) solution. Beispiel 5.2.5 Verwendung des Prolog-Prädikats "sql_querydistinct" In dem Beispiel 5.2.5 wird die Konstruktion einer SQL-Select-Operation durch das PrologPrädikat "sql_querydistinct" beschrieben. Angenommen es existieren mehrere Datensätze in der Tabelle "person", deren Attribut "name" als Wert die Zeichenkette 'Scheuber' besitzt, so wird dieser Name nur einmal selektiert, da es ansonsten zu Duplikaten in den selektierten Datensätzen kommen würde. Wird das Prädikat "sql_querydistinct" über mehrere Attribute, wie zum Beispiel Name und Vorname definiert, so müssen sowohl das Attribute Name als auch Vorname in ihren Werten übereinstimmen, damit der Datensatz nicht zweimal selektiert wird. Durch das Prädikat "sql_lastmsg" kann ermittelt werden, ob die letzte SQL-Operation erfolgreich durchgeführt werden konnte. Dieses Prädikat ist erforderlich, da Oracle zwischen einem lokalen und einem globalen Rollback unterscheidet (siehe Kapitel 8 Abschnitt 8.2). Es stellt die einzige Möglichkeit dar, zu überprüfen, ob ein lokales Rollback stattgefunden hat. Die zwei ersten Rückgabeparameter des Prädikats beinhalten den Oracle-Fehlercode und die dazugehörige Fehlermeldung, falls die SQL-Operation fehlgeschlagen ist. Der dritte Rückgabeparameter beinhaltet die Anzahl der manipulierten Tupel, falls die SQL-Operation erfolgreich war, und wird ansonsten mit dem Wert "0" unifiziert. 73 Inhaltsverzeichnis Andrea Scheuber 6 Übersetzung von Chimera-Schemata in Oracle8-SQL-Schemata In diesem Kapitel wird eine Methode vorgestellt, wie die grundlegenden Konzepte des Chimera Data Dictionary (CDD), die aus einer Schemadefinition in der Chimera-Sprache extrahiert werden, in eine Schemadefinition des Datenbanksystems Oracle8 abgebildet werden können. Dabei wird der Schwerpunkt auf Wertetypen, Werteklassen, Objektklassen und die Umsetzung von Klassenhierarchien eingegangen. Die interessanten Aspekte dieser Übersetzung liegen insbesondere in der Realisierung der Klassenhierarchien, da Oracle8 zur Zeit keinerlei Vererbungsmechanismen bietet. Die Übersetzung der Integritätsbedingungen und Trigger stellt einen weiteren interessanten Aspekt dar, da diese Chimera-Konzepte in ihrer Semantik mächtiger sind, als die Konzepte, die Oracle8 zu bieten hat. Auf die Übersetzung von Integritätsbedingungen und Triggern wird in Kapitel 9 eingegangen. 6.1 Datentypen Eine grundlegende Voraussetzung für die Übersetzung eines Chimera-Schemas in ein Oracleoder Phoenix-Schema, ist die Abbildung der Built-in-Datentypen von Chimera auf die Builtin-Datentypen der beiden Datenbanksysteme, da die Konzepte zur Abbildung von Wertetypen, Werteklassen und Objektklassen auf diesen basieren. Bei der Abbildung nach Oracle tauchen Probleme auf, da kein in einigen Fällen kein äquivalenter Datentyp oder kein äquivalentes Konzept existiert. Eines dieser Probleme ist die Realisierung des Datentyps "string" ohne Längenbeschränkung, da diese von Oracle bei der Definition einer Zeichenkette von variabler Länge gefordert wird. Um dieses Problem zu umgehen, wurden die folgenden Überlegungen angestellt. Der erste Lösungsansatz war, eine Standardlänge von 100 Zeichen bei der Übersetzung des Da74 Inhaltsverzeichnis tentyps "string" einzuführen. Da dieser Ansatz jedoch ineffizient im Speicherplatzverbrauch ist und auch nicht garantiert werden kann, daß dieser Wertebereich für alle Attribute ausreichend ist, haben wir in unserer Implementation festgelegt, daß eine Maximallänge bei Verwendung des Datentyps "string" vom Benutzer festgelegt werden muß. Dies ist die beste Lösung, da der Platzbedarf am besten von jemanden abgeschätzt werden kann, der das Datenbankschema erstellt und die Aufgaben kennt, die es erfüllen muß. Ein weiteres Problem ist die Realisierung des Datentyps "real". Dieser Datentyp existiert zwar zur Definition von PL/SQL-Variablen, kann aber nicht als Wertebereich eines Attributes in einer Oracle8-SQL-Schemadefinition dienen. Diesen Zweck erfüllt der Oracle-Datentyp "number(m,n)", durch den Wertebereiche definiert werden können, die dem Datentyp "real" entsprechen. Der große Nachteil ist, daß auch hier wieder Maximallängen angegeben werden müssen, die den Vor- und Nachkommabereich des Wertebereichs einschränken. Dadurch wurden wir gezwungen, bei der Übersetzung des Datentyps "real" Standardwerte für Vor- und Nachkommastellen zu definieren, die daraufhin mit m=10 und n=10 festgelegt worden sind. Da es in Oracle auch keinen äquivalenten Datentyp für den Datentyp "boolean" gibt, muß dieser ebenfalls auf andere Weise umgesetzt werden. Zur Auswahl stehen die Datentypen "char(1)" und "number(1)" mit den Werten "Y" bzw. "1" für wahr und den Werten "N" und "0" für falsch. Da keiner der Datentypen einen Vorteil gegenüber dem anderen bietet, ist der Datentyp "char(1)" ohne besonderen Grund ausgewählt worden. Die folgende Tabelle stellt die Built-in-Datentypen von Chimera den Typen der Datenbanksysteme zu besseren Übersicht noch einmal gegenüber. ChimeraBonn Phoenix Oracle boolean boolean char(1) character character char string atom --- string(n) atom(n) varchar2(n) integer integer number real real number(X,Y) Tabelle 6.1.1: Übersetzung der Chimera Datentypen 6.2 Wertetypen In diesem Kapitel wird die Übersetzung des Chimera-Konzepts Wertetyp vorgestellt. Um das Chimera-Konzept Wertetyp umzusetzen, ist das Oracle-Konzept Objekttyp ausgewählt wor75 Inhaltsverzeichnis den. Die Gemeinsamkeiten beider Konzepte bestehen darin, daß sie beide zur Definition eines benutzerdefinierten, abstrakten Datentyps dienen, der selbst keine Instanzen besitzt, sondern nur eine Strukturbeschreibung darstellt. Sowohl der Wertetyp als auch der Objekttyp kann bei der Definition des Wertebereichs von Attributen in Objektklassen, bzw. in Relationen, eingesetzt werden. Ein gravierender Unterschied zwischen dem Chimera-Konzept Wertetyp und dem Oracle-Konzept Objekttyp besteht in der Definition von Integritätsbedingungen. Die Integritätsbedingungen eines Wertetypen werden direkt an seine Definition gekoppelt und können über einzelne Attribute definiert werden. Das Konzept Objekttyp unterstützt Integritätsbedingungen nur indirekt, da diese erst bei Einsatz eines Objekttyps als Wertebereich eines Attributs definiert werden können und auch nur über den gesamten Objekttypen und nicht über einzelne Attribute. So ist es zum Beispiel nicht möglich bei einem Objekttypen mit mehreren Attributen über nur ein Attribut eine Integritätsbedingung vom Typ "unique" oder "not null" zu definieren. Der einzige Integritätsbedingungstyp, den Oracle8 zur Verfügung stellt und der auf einzelne Attribute eines Objekttyps zugreifen kann, ist die Bedingung "check", da sie in der Lage ist, auf alle Werte der aktuellen Instanz zuzugreifen. Durch die Definition eines boolschen Ausdrucks in Form einer "check"-Bedingung über den zulässigen Attributwerten eines Objekttyps, kann die Bereichsbeschränkung eines Wertetypen aus einem Chimera-Schema umgesetzt werden. Allerdings muß die "check"Bedingung bei jedem Einsatz des Objekttyps als Wertebereich eines Attributes erneut definiert werden. Ein weiterer Unterschied zwischen Wertetyp und Objekttyp besteht durch Einschränkungen im Konzept Objekttyp in Bezug auf zulässige Verschachtelungen der Objekttypen. Das Datenmodell von Chimera erlaubt, daß ein Wertetyp sich selbst als Wertebereich eines Attributes besitzen darf. Es liegt dann eine rekursive Definition eines Wertetyps vor, die in Oracle8 nicht zulässig ist. Solange man diese Einschränkung beachtet, ist es erlaubt Objekttypen beliebig ineinander zu schachteln. Anhand des folgenden Beispiels wird die Vorgehensweise zur Übersetzung eines Objekttyps noch einmal verdeutlicht. Chimera-Wertetyp define value type vt_adresse: record_of ( strasse: string(30), hausnr: integer, plz: integer ) end; Oracle8-Objekttyp CREATE TYPE vt_adresse AS OBJECT ( strasse varchar2(30), hausnr number, plz number ); Beispiel 6.2.1: Übersetzung eines Wertetyps in einen Objekttyp Im oben angegebenen Beispiel wird der Wertetyp "adresse" definiert. Er besteht aus drei Attributwerten, die seine Strukturbeschreibung darstellen. Der dazugehörige Objekttyp wird unter dem Namen des Wertetyps definiert und beinhaltet als Strukturbeschreibung die gleiche Anzahl von Attributen, die auch mit den gleichen Attributnamen des Wertetyps bezeichnet werden. Die Übersetzung der Attributwertebereiche des Wertetyps in Oracle-Datentypen erfolgt wie schon in Kapitel 6.1 beschrieben. 76 Inhaltsverzeichnis 6.3 Werteklassen Die Umsetzung des Chimera-Konzepts Werteklasse erfolgt sowohl in Phoenix als auch in Oracle durch extensionale Relationen bzw. Tabellen. Die Gemeinsamkeiten zwischen Werteklassen und Tabellen besteht darin, daß sowohl Werteklassen als auch Tabellen aus Attributen bestehen und Instanzen besitzen. Die Instanzen einer Werteklasse werden durch die Operationen "add" und "drop" erzeugt und gelöscht. Die Datensätze einer Tabelle können durch die Standard DML-Operationen "insert", "delete" und "update" erzeugt, gelöscht und modifiziert werden. Es ist offensichtlich, daß die Operation "add" der Operation "insert" entspricht und die Operation "drop" durch die Operation "delete" realisiert werden kann. Des weiteren ist es möglich, sowohl über Werteklassen als auch Tabellen Integritätsbedingungen zu definieren. Der Unterschied zwischen Werteklassen und Tabellen besteht darin, daß eine Werteklasse ein Datentyp mit fest definierten Werten ist, also eine Art Aufzählungstyp, der als Wertebereich für ein Attribut in einer Objektklasse benutzt werden kann. Eine Tabelle, die eine Werteklasse realisiert, ist kein Datentyp, sondern eine Struktur, in der Daten abgelegt werden. Um eine Verbindung zwischen den Tabelle herzustellen, die Objektklassen und Werteklassen realisieren, wird in der Tabelle der Werteklasse ein zusätzliches Attribut eingeführt. Dieses Attribut wird als Primärschlüssel definiert. Das Attribut in der Tabelle der Objektklasse, welches eine Werteklasse als Wertebereich besitzt, bekommt als Attributbereich den Datentyp des Primärschlüssels aus der Tabelle der Werteklasse zugewiesen. Über diese gleichwertigen Attribute kann nun eine Verbindung zwischen den beiden Tabellen in Form eines Fremdschlüssels hergestellt werden. Diese Vorgehensweise wird unbedingt benötigt, wenn eine Werteklasse mehr als ein Attribut besitzt. Ansonsten kann kein Fremdschlüssel definiert werden, der die Instanzen der Tabelle der Werteklasse korrekt mit den Instanzen der Tabelle der Objektklasse in Verbindung setzt. Besteht eine Werteklasse nur aus einem Attribut, wird die gleiche Vorgehensweise gewählt, um ein einheitliches Übersetzungsverfahren zu haben. In diesem Fall wäre es von Vorteil direkt über das einzelne Attribut zu referenzieren, da dessen Werte eindeutig sein müssen und sich dadurch als Fremdschlüssel eignen. Das folgende Beispiel verdeutlicht die Vorgehensweise zur Übersetzung einer Chimera-Werteklasse in eine Oracle-Tabelle. Chimera-Werteklasse define value class vc_abteilung: record_of ( bereich: string(30), leiter: string(30) ) end; Oracle-Tabelle CREATE TABLE vc_abteilung ( vid NUMBER PRIMARY KEY, bereich VARCHAR2(30), leiter VARCHAR2(30) ); Beispiel 6.3.1: Übersetzung einer Chimera-Werteklasse in eine Oracle-Relation Die Übersetzung der Werteklasse "abteilung" erfolgt durch die Definition einer Tabelle des selben Namens. Die beiden Attribute der Werteklasse, "bereich" und "leiter" werden durch Attribute in der Tabelle realisiert, die den gleichen Namen tragen. Die Wertebereiche der Attribute werden wie in Kapitel 6.1 beschrieben übersetzt. Das zusätzliche Attribut 77 Inhaltsverzeichnis in der Tabellendefinition wird unter dem Attributnamen "vid" (value identificator) und als Primärschlüssel eingeführt. Eine Alternative zu dieser Vorgehensweise wäre es, die Struktur einer Werteklasse in Form eines Objekttyps abzubilden und über eine Objekttabelle zu realisieren, deren Struktur durch den Objekttyp vorgegeben ist. In dieser Objekttabelle könnten dann die Instanzen der Werteklasse verwaltet werden. Der Vorteil dieser Vorgehensweise wäre, daß keine "vid" eingeführt werden müßte, da die Instanzen der Objekttabelle bereits einen Objektidentifikator besitzen, über den die Verbindung zwischen Tabelle und Objekttabelle hergestellt werden könnte. Der Nachteil dieser Vorgehensweise ist wieder das Problem, daß Integritätsbedingungen nicht über Objekttypen und ihren einzelnen Attributen definiert werden können, sondern nur über den gesamten Objekttypen, wenn er als Wertebereich eines Attributs eingesetzt wird. Um diese Einschränkung zu vermeiden, ist dieser Ansatz wieder verworfen worden. Eine weitere Alternative wäre es gewesen, die Umsetzung von Werteklassen über "check"Bedingungen auf der Oracle-Seite zu implementieren. Da allerdings der Wertebereich einer Werteklasse durch die Operationen "add" und "drop" nicht nur bei der Erstellung des Datenbankschemas festgelegt, sondern auch noch danach manipuliert werden kann, wurde die Übersetzung durch eine Tabelle und Integritätsbedingungen vorgezogen, da sonst eine Änderung in einer Werteklasse mindestens eine oder mehrere Modifikationen an der Definition des Datenbankschemas nach sich ziehen kann. Des weiteren ist es einfacher, einen neuen Datensatz in eine Tabelle abzulegen, als alle "check"-Bedingungen, die auf einer Werteklasse basieren, zu modifizieren. Ein weiteres Problem taucht bei dieser Vorgehensweise bei der Definition von Integritätsbedingungen auf, da sowohl die Daten der Werteklasse als auch ihrer Integritätsbedingungen bei der Implementation einer "CHECK"-Bedingung berücksichtigt werden müssen. Aus diesen Gründen wurde die Idee der Implementation von Werteklassen durch "check"-Bedingungen wieder verworfen. 6.4 Objektklassen und Klassenhierarchien Das Chimera-Konzept der Objektklasse wird in Oracle durch die Kombination von Tabellen und Sichten umgesetzt. Die Gemeinsamkeiten von Objektklassen und Tabellen besteht darin, daß beide Konzepte zur Speicherung und Verwaltung von Daten dienen. Der Bezeichner einer Tabelle, die eine Objektklasse repräsentiert, setzt sich aus dem Präfix "oc_" und dem Namen der Objektklasse zusammen, um sie von den Bezeichnern der dazugehörigen Sichten zu unterscheiden. Sowohl Objektklassen als auch Tabellen bestehen aus Attributen, deren Wertebereiche entweder durch Built-in-Datentypen oder benutzerdefinierte Datentypen definiert werden können. Für jede Objektklasse wird genau eine Tabelle und eine Sicht erstellt. Die Tabellen enthalten bis auf eine Ausnahme nur die Attribute, die innerhalb der Objektklassen auch definiert worden sind. Zusätzlich zu den im Chimera-Schema definierten Attributen erhält eine Tabelle, die eine Objektklasse repräsentiert, ein zusätzliches Attribut in dem der Objektidentifikator (OID) gespeichert wird. Dieser Objektidentifikator stellt bei der Definition einer Sicht die Verbindung zwischen den Instanzen der Tabellen her, um sie der Klassenhierarchie entsprechend zusammenzuführen. Der eindeutige Wert eines Objektidentifikators wird durch das Oracle-Konzept "sequence" erzeugt. Auf eine "sequence" kann durch die Funktionen "currval" und "nextval" zugegriffen werden, wobei die Funktion 78 Inhaltsverzeichnis "currval" den aktuellen Wert der angegebenen "sequence" zurück liefert und die Funktion "nextval" den aktuellen Wert um einen festgelegten Wert inkrementiert und das Ergebnis als neuen Wert zurück liefert. 6.4.1 Abbildung von Chimera-Objektklassen auf Oracle8-Tabellen Die benutzerdefinierten Wertebereiche der Attribute einer Objektklasse können durch Wertetypen, Werteklassen und andere Objektklassen repräsentiert werden. Ist der Wertebereich eines Attributs durch einen Wertetypen festgelegt worden, so kann einfach der Bezeichner des Wertetyps als Wertebereich benutzt werden, da ein entsprechender Objekttyp mit dem gleichen Bezeichner auf der Oracle-Seite bereits definiert worden ist (siehe Kapitel 6.2). Das folgende Beispiel zeigt die Umsetzung einer Objektklasse, in der ein Attribut einen Wertetyp als Wertebereich besitzt. Chimera-Objektklasse define object class person attributes name: string(30), vorname: string(30), adresse: vt_adresse end; Oracle-Tabelle CREATE TABLE oc_person ( oid NUMBER PRIMARY KEY, name VARCHAR2(30), vorname VARCHAR2(30), adresse vt_adresse ); Beispiel 6.4.1: Übersetzung eines Wertetyps als Wertebereich eines Attributs In diesem Beispiel ist der in Kapitel 6.1 definierte Objekttyp "vt_adresse" als Wertebereich des Attributs "adresse" verwendet worden. Dieser Wertebereich umfaßt die zusätzlichen Attribute "strasse", "hausnr" und "plz", auf die nur zugegriffen werden kann, wenn eine Tupelvariable innerhalb einer DML-Operation oder Anfrage definiert worden ist. Der Ausdruck, mit dem ein Attribut eines Objekttyps angesprochen werden kann, besteht aus den Komponenten Tupelvariable, Name des Objekttyps und Name des Attributs. Auf das vorangestellte Beispiel bezogen, wird auf die Werte des Attributs "strasse" aus der Tabelle "oc_person" wie folgt zugegriffen: SELECT V.adresse.strasse FROM oc_person V; Ist der Wertebereich eines Attributs durch eine Werteklasse festgelegt worden, so wird dem entsprechenden Attribut in der Tabelle, welche die Objektklasse abbildet, der Wertebereich "number" zugewiesen. Dies ist eine Voraussetzung, um einen Fremdschlüssel zwischen dem Attribut, welches als Wertebereich eine Werteklasse besitzt, und dem Primärschlüssel der Tabelle, welche die Werteklasse repräsentiert, definieren zu können, da beide Attribute den gleichen Datentyp als Wertebereich besitzen müssen (siehe Kapitel 6.3). 79 Inhaltsverzeichnis Chimera-Objektklasse define object class angestellter superclasses person attributes abteilung: vc_abteilung, gehalt: integer end; Oracle-Tabelle CREATE TABLE oc_angestellter ( oid NUMBER PRIMARY KEY, abteilung INTEGER REFERENCES vc_abteilung, gehalt NUMBER ); Beispiel 6.4.2: Übersetzung einer Werteklasse als Wertebereich eines Attributs In diesem Beispiel ist in der Chimera-Objektklasse "angestellter" der Wertebereich des Attributs "abteilung" durch die Werteklasse "vc_abteilung" festgelegt worden. Das Attribut "abteilung" in der Oracle-Tabelle "angestellter" bekommt als Wertebereich den Datentyp "number" zugewiesen. Die Verbindung zwischen der Tabelle "angestellter" und der Tabelle "vc_abteilung" wird durch die Definition eines Fremdschlüssels zwischen dem Attribut "abteilung" und dem Primärschlüssel der Werteklasse hergestellt. Die genaue Übersetzung dieser Werteklasse in eine Oracle-Tabelle ist in dem Kapitel 6.3 zu finden. 6.4.2 Abbildung einer Chimera-Klassenhierarchie auf Oracle8-Sichten Durch die Definition von Oberklassen innerhalb der Definition einer Objektklasse wird die eigentliche Hierarchie eines Chimera-Datenbankschemas aufgebaut, welche durch die Vererbung von Attributen organisiert wird. Da ein solcher Mechanismus für Oracle8 nicht existiert, werden Sichten benutzt, um diesen Mechanismus zu implementieren. Eine Sicht, die eine Objektklasse abbildet, enthält sowohl die Attribute der Objektklasse als auch alle Attribute ihrer Oberklassen. Auf diese Weise wird die Struktur der Klassenhierarchie umgesetzt. Der Bezeichner einer Sicht ist der Name der Objektklasse, die durch sie repräsentiert wird. Besitzt eine Objektklasse keine Oberklassen, so wird trotzdem ein Sicht über ihren Attributen erstellt, um das Übersetzungsverfahren zu vereinfachen. person angestellter student Beispiel 6.4.1: Klassenhierarchie 80 Inhaltsverzeichnis So werden für die Abbildung der Klassenhierarchie in Beispiel 6.4.1 sowohl die drei Tabellen "oc_person", "oc_angestellter" und "oc_student", als auch die drei Sichten "person", "angesteller" und "student" benötigt. Bei der Abbildung einer Klassenhierarchie gibt es zwei alternative Vorgehensweisen. Die erste besteht darin, die Definition der Sicht auf den bereits existierenden Sichten aufbauen zu lassen. Diese Vorgehensweise hätte den Vorteil, daß man nur die direkten Oberklassen bei der Definition der Sicht beachten muß, da diese bereits alle Attribute ihrer Oberklassen besitzt. Der Nachteil dieser Vorgehensweise ist, daß Modifikationen am Datenbestand einer Sicht, die auf anderen Sichten basiert, wesentlich ineffizienter zur Laufzeit sind als Modifikationen am Datenbestand einer Sicht, die nur auf Tabellen basiert. Basiert eine Sicht auf anderen Sichten, so müssen die modifizierten Daten erst alle anderen beteiligten Sichten passieren, bevor sie in den Basistabellen ankommen. Dadurch ergeben sich in Abhängigkeit von der Länge dieser Kette von Sichten die schlechten Laufzeiten. Aus diesem Grund ist die zweite Vorgehensweise gewählt worden, in der alle Sichten des Datenbankschemas ausschließlich auf Tabellen basieren. Diese Vorgehensweise ist zwar aufwendiger bei der Übersetzung des Datenbankschemas, da erst alle beteiligten Oberklassen einer Objektklasse und ihre Attribute zusammengestellt werden müssen, um eine Sicht zu definieren, aber dafür verbessert sich die Laufzeit der DML-Operationen. Da die Definition des Datenbankschemas nur einmal zur Erstellung der Datenbank übersetzt wird, die DMLOperationen hingegen laufend benutzt werden, liegt der Vorteil dieser Lösung auf der Hand. Anhand der folgenden Beispiele, die sich auf die vorangestellte Klassenhierarchie aus Beispiel 6.2.1 bezieht, wird die Umsetzung einer Klassenhierarchie durch den Einsatz von Sichten genauer erläutert. Chimera-Objektklasse Oracle-Tabelle Oracle-Sicht CREATE VIEW person AS CREATE TABLE oc_person define object class ( oid, name, vorname, ( person strasse, hausnr, plz ) oid NUMBER PRIMARY KEY, attributes SELECT name VARCHAR2(30), name: string(30), P.oid, vorname VARCHAR2(30), vorname: string(30), P.name, adresse vt_adresse adresse: vt_adresse P.vorname, ); end; P.adresse.strasse, P.adresse.hausnr, P.adresse.plz FROM oc_person P; Beispiel 6.4.2: Übersetzung der Objektklasse Person In dem Beispiel 6.4.2 wird beschrieben, wie die Objektklasse "person" umgesetzt wird, die keine Oberklasse besitzt und somit auch keine Attribute aus anderen Klassen erbt. Die Sicht, die eine solche Objektklasse repräsentiert, basiert ausschließlich auf den Attributen ihrer Basistabelle, die alle explizit zur Erstellung der Sicht selektiert werden. In diesem Beispiel werden aus der Tabelle "oc_person" die Attribute "oid", "name" und "vorname" selektiert. Da das Attribut "adresse" durch den Wertebereich des Objekttyps "vt_adresse" festgelegt wird, müssen alle Attribute des Objekttyps explizit mit selektiert 81 Inhaltsverzeichnis werden, damit die Attribute und nicht der Objektidentifikator des Objekttyps Bestandteil der Sicht sind. Chimera-Objektklasse Oracle-Tabelle CREATE TABLE define object class oc_angestellter angestellter ( superclasses oid NUMBER PRIMARY KEY, person abteilung INTEGER attributes REFERENCES abteilung:vc_abteilung, vc_abteilung, gehalt: integer gehalt NUMBER end; ); Oracle-Sicht CREATE VIEW angestellter AS ( oid, name, vorname, strasse, hausnr, plz, bereich, leiter, gehalt ) SELECT P.oid, P.name, P.vorname, P.adresse.strasse, P.adresse.hausnr P.adresse.plz, V.bereich, V.leiter, A.gehalt FROM oc_person P, oc_angestellter A, vc_abteilung V WHERE P.oid = A.oid AND A.abteilung = V.vid Beispiel 6.4.3: Übersetzung der Objektklasse Angestellter In dem Beispiel 6.4.3 wird beschrieben, wie eine Objektklasse umgesetzt wird, die eine andere Objektklasse als Oberklasse besitzt. In diesem Fall besitzt die Objektklasse "angestellter" die Objektklasse "person" als Oberklasse. Das hat für die Definition der Sicht "angestellter" zur Folge, daß nicht nur alle Attribute der Tabelle "oc_angestellter" zur Definition der Sicht selektiert werden müssen, sondern auch alle Attribute der Tabelle "oc_person", um auf diese Weise die Attribute der übergeordneten Klasse zu vererben. Die einzige Ausnahme bei der Selektion der Attribute bildet das Attribute "oid". Da durch dieses Attribut die Verbindung zwischen den Datensätzen der Basistabellen hergestellt wird, wenn der Wert der beiden "oid"s in den unterschiedlichen Tabellen identisch ist, wäre es nicht sinnvoll dieselbe "oid" mehrfach anzuzeigen. Da in unserer Implementation grundsätzlich die Spalten, der Objektklassen zuerst selektiert werden, die keine anderen Objektklassen als Oberklassen besitzen, wird auch immer die "oid" dieser Objektklasse als erstes Attribut mit selektiert. In diesem Beispiel werden deshalb die Attribute "oid", "name", "vorname", die Attribute des Objekttyps "vt_adresse" aus der Basistabelle "oc_person" und das Attribut "gehalt" aus der Basistabelle "oc_angestellter" selektiert. Die Verbindung zwischen den Attributen aus den beiden Basistabellen wird über die Bedingungsklausel, die zur Definition der Sicht benötigt wird erstellt. In dieser wird gefordert, daß die "oid" eines Tupels aus der Basistabelle "oc_person" identisch zu der "oid" eines Tupels aus der Basistabelle 82 Inhaltsverzeichnis "oc_angestellter" sein muß, damit ein Tupel aus der Kollektion dieser Attribute in der Sicht zusammengestellt werden kann. Ein weiterer interessanter Aspekt des Beispiel 6.4.3 besteht in der Verwendung einer Werteklasse als Wertebereich eines Attributes in einer Objektklasse. In einem solchen Fall werden nicht nur die Attribute der Objektklasse und ihrer Oberklassen selektiert, sondern auch alle Attribute der beteiligten Werteklasse mit Ausnahme der "vid" werden als Attribute in die Definition der Sicht mit eingebunden. Die Verbindung der Tupel der beiden Tabellen, welche die Objektklasse und die Werteklasse darstellen, erfolgt über eine zusätzliche Bedingung in der Bedingungsklausel der SQL-"select"-Operation, durch welche die Daten einer Sicht selektiert werden. Diese zusätzliche Bedingung legt fest, daß die "vid" aus der Tabelle, welche die Werteklasse repräsentiert, identisch zu dem Wert des Attributes sein muß, dessen Wertebereich in der Objektklasse durch die Werteklasse festgelegt ist. Für das konkrete Beispiel 6.4.3 bedeutet dieses, daß die beiden Attribute "bereich" und "leiter" aus der Tabelle "vc_abteilung" zusätzlich in die Definition der Sicht "angestellter" mit einfließen. Die zusätzliche Bedingung in der Bedingungsklausel fordert die Gleichheit der Attributwerte "vid" und "abteilung", um die konkreten Daten der Werteklasse "vc_abteilung" in die Sicht mit einzubinden. Chimera-Objektklasse define object class student superclasses angestellter attributes matrikel_nr: integer end; Oracle-Tabelle Oracle-Sicht CREATE VIEW student AS CREATE TABLE oc_student ( oid, name, vorname, ( strasse, hausnr, plz, oid NUMBER PRIMARY KEY, bereich, leiter, matrikel_nr NUMBER gehalt, matrikel_nr ) ); SELECT P.oid, P.name, P.vorname, P.adresse.strasse, P.adresse.hausnr P.adresse.plz, V.bereich, V.leiter, A.gehalt, S.matrikel_nr FROM oc_person P, oc_angestellter A, vc_abteilung V, oc_student S WHERE P.oid = A.oid AND P.oid = S.oid AND A.abteilung = V.vid; Beispiel 6.4.4: Übersetzung der Objektklasse Student In dem Beispiel 6.4.4 wird beschrieben, wie eine Objektklasse umgesetzt wird, deren Oberklasse wiederum eine andere Objektklasse als Oberklasse besitzt. Dadurch ergibt sich eine Kette von Objektklassen. Die Objektklasse "student" besitzt sowohl die Objektklasse 83 Inhaltsverzeichnis "angestellter" als direkte Oberklasse, als auch die Objektklasse "person" als indirekte Oberklasse, da diese eine direkte Oberklasse der Objektklasse "angestellter" ist. Das hat für die Definition der Sicht "student" zur Folge, daß die Attribute der Tabellen "oc_student", "oc_angestellter" und "oc_person" selektiert werden müssen. Daraus ergibt sich, daß die Attribute "oid", "name", "vorname" und die Attribute des Attributs "adresse" aus der Basistabelle "oc_person" selektiert werden müssen. Hinzu kommen die Attribute "bereich" und "leiter" aus der Tabelle "vc_abteilung". Das Attribut "gehalt" aus der Basistabelle "oc_angestellter" und das Attribut "matrikel_nr" aus der Basistabelle "student" werden auch noch in die Definition der Sicht mit eingebunden. In der Bedingungsklausel der "select"-Operation, durch welche die Sicht definiert wird, werden die Datensätze der einzelnen Basistabellen durch die Forderung nach der Gleichheit der "oid"s in allen beteiligten Tabellen miteinander verbunden. 6.4.3 Umsetzung von DML-Operationen auf Sichten Die Chimera DML-Operationen "create", "modify" und "delete", werden in die SQL-Operationen "insert", "update" und "delete" übersetzt. Eine SQL-Operation wird immer an die entsprechende Sicht und nicht an die Basistabellen gerichtet, da die Sicht alle Attribute der Objektklasse, inklusive der geerbten Attribute der Oberklassen, enthält. Die hier vorgestellte Vorgehensweise ist nur durch das neue Oracle8-Konzept der Instead-ofTrigger möglich. Diese Trigger sind dafür zuständig, die einzelnen Attributwerte einer Sicht den richtigen Attributen der Basistabellen zuzuordnen. Dies kann nicht automatisch von Oracle übernommen werden, da in der Regel mehr als eine Basistabelle zur Definition der Sicht benutzt wird und auch nicht alle Primärschlüssel der Basistabellen beteiligt sind. Für jede DML-Operation wird ein entsprechender Instead-of-Trigger bei der Übersetzung eines Chimera-Schemas in ein Oracle8-Schema automatisch erzeugt. Die Instead-of-Trigger einer Sicht überladen die rudimentären "view-update"-Funktionen, die von Oracle selbst zur Verfügung gestellt werden und nur unter den oben bereits genannten Bedingungen funktionieren. Die Konstruktion eines Instead-of-Insert-Triggers wird wie folgt umgesetzt. Der Bezeichner des Instead-of-Triggers setzt sich aus dem Bezeichner der Sicht und dem Typ der DMLOperation, die durch den Trigger implementiert wird, zusammen. Diese Konvention zur Erstellung eines Triggerbezeichners wurde festgelegt, da ein eindeutiger Bezeichner für jeden Trigger innerhalb des Datenbankschemas vergeben werden muß. Ein Instead-of-InsertTrigger verteilt die Attributwerte der Sicht, über der er definiert worden ist, an die entsprechenden Basistabellen. Dementsprechend muß der Trigger genau so viele "Insert"Operationen beinhalten, wie auch Basistabellen betroffen sind. Das folgende Beispiel zur Definition eines Instead-of-Insert-Triggers verdeutlicht, wie die Verteilung der Werte in die entsprechenden Basistabellen umgesetzt wird. 84 Inhaltsverzeichnis CREATE OR REPLACE TRIGGER student_insert INSTEAD OF INSERT ON student vid_abteilung NUMBER; BEGIN INSERT INTO oc_person VALUES( new.oid, :new.name, :new.vorname, vt_adresse( :new.adresse.strasse, :new.adresse.hausnr, :new.addresse.plz) ); SELECT INTO FROM WHERE AND V.vid vid_abteilung vc_abteilung V V.bereich = :new.bereich V.leiter = :new.leiter; INSERT INTO oc_angestellter VALUES( new.oid, vid_abteilung, :new.gehalt ); INSERT INTO oc_student VALUES( new.oid, :new.matrikel_nr ); END; Beispiel 6.4.1: Instead-of-Insert-Trigger der Sicht Student Der Trigger "student_insert" beinhaltet drei "Insert"-Operationen, welche die neuen Daten der Sicht im Falle einer "Insert"-Operation auf die drei beteiligten Basistabellen "oc_person", "oc_angestellter" und "oc_student" verteilt. Generell wird der neue Wert des Attributes "oid" in der Sicht an alle Basistabellen weitergegeben und die anderen Attribute werden an die einzelnen Basistabellen verteilt. Die erste "Insert"-Operation des Triggers richtet sich an die Tabelle "oc_person". Dabei ist zu beachten ist, daß die drei Attribute "strasse", "hausnr" und "plz" dem Attribut "adresse" zugeordnet werden müssen, dessen Wertebereich durch den Objekttypen "vt_adresse" festgelegt ist. Die zweite Operation des Triggers besteht in einer Anfrage an die Tabelle "vc_abteilung", die eine Werteklasse repräsentiert. Die Aufgabe dieser Anfrage ist es, die entsprechende "vid" zu den Werten der Sichtattribute "bereich" und "leiter" herauszufinden, um diese als Wert dem Attribut "abteilung" in der Basistabelle "oc_person" zuzuordnen. Dieser Vorgang ist erforderlich, damit der Wert des Fremdschlüssels, der die Verbindung zwischen den Tabellen "oc_person" und "vc_abteilung" herstellt, nicht gegen Integritätsbedingungen verstößt. Die dritte Operation des Triggers ist eine "insert"-Operation, die sich an die Tabelle "oc_angestellter" richtet. In dieser Operation wird die Variable "vid_abteilung", die in der vorangestellten "select"-Operation mit der selektierten 85 Inhaltsverzeichnis "vid" initialisiert wird, als Wert des Attributs "abteilung" verwendet. Die letzte "insert"-Operation verteilt zusammen mit der neuen "oid" das Attribut "matrikel_nr" an die Basistabelle "oc_student". Ein Instead-of-Update-Trigger wird durch eine "update"-Operation an eine Sicht ausgelöst. Da es sich bei Instead-of-Triggern generell um "row-level"-Trigger handelt, wird dieser Trigger nicht nur einmal pro aufgerufene Operation, sondern pro Tupel ausgelöst, welches in der Sicht von der "update"-Operation betroffen ist. Innerhalb eines Instead-of-UpdateTriggers wird jeder einzelne Wert eines modifizierten Tupels daraufhin überprüft, ob er durch eine "update"-Operation modifiziert worden ist. Dies wird durch die Funktionen "old" und "new" ermöglicht, die den alten Wert des jeweiligen Attributs bei Beginn der aktuellen Transaktion und den aktuellen Wert des Attributs nach der "Update"-Operation liefern. Diese Werte werden miteinander verglichen und falls sie unterschiedlich sind, wird eine "update"-Operation an die entsprechende Basistabelle gerichtet, damit die Modifikationen am Datenbestand der Sicht auf die Basistabellen übertragen werden. Dabei wird der Wert der "oid" benutzt, um eine Verbindung zwischen den Tupeln der Sicht und den Tupeln der Basistabellen herzustellen. Aus diesem Grund bildet das Attribut "oid" eine Ausnahme bei den zu überprüfenden Attributwerten. Die "oid" wird automatisch über eine "sequence" generiert, und darf nicht modifiziert werden. Deshalb wird eine Modifikation dieses Attributwerts nicht überprüft und somit auch nicht umgesetzt. In dem folgenden Beispiel wird ein Ausschnitt aus der Definition des Instead-of-Update-Triggers der Sicht Student dargestellt. Der Trigger wird nicht vollständig vorgestellt, da ansonsten die Übersicht innerhalb des Beispiels verloren geht. Deshalb wurde das Beispiel auf die interessanten Aspekte beschränkt. CREATE OR REPLACE TRIGGER student_update INSTEAD OF UPDATE ON student BEGIN IF :new.name != :old.name THEN UPDATE oc_person SET name = :new.name WHERE oid = :old.oid; END IF; ... IF :new.vt_adresse.strasse != :old.vt_adresse.strasse THEN UPDATE oc_person P SET P.vt_adresse.strasse = :new.adresse.strasse WHERE P.oid = :old.oid; END IF; ... 86 Inhaltsverzeichnis IF :new.bereich != :old.bereich THEN UPDATE oc_angestellter A SET abteilung = ( SELECT vid FROM vc_abteilung V WHERE V.bereich = :new.bereich AND V.leiter = :new.leiter ) WHERE A.oid = :old.oid; END IF; ... IF :new.matrikel_nr != :old.matrikel_nr THEN UPDATE oc_student SET matrikel_nr = :new.matrikel_nr WHERE oid = :old.oid; END IF; END; Beispiel 6.4.2: Ausschnitt des Instead-of-Update-Trigger der Sicht "student" Die erste und die letzte "update"-Operation des Beispiel 6.4.2 sind einfach zu realisieren, da die Wertebereiche der beteiligten Attribute durch einen Built-in-Datentyp von Oracle festgelegt sind. Ihre Werte können einfach an die entsprechenden Attribute in den Basistabellen weitergereicht werden, deren Wertebereiche durch die gleichen Built-in-Datentypen festgelegt sind. Die interessanten Aspekte des Instead-of-Update-Trigger der Sicht "student" bestehen in den "update"-Operationen, die für Werte von benutzerdefinierten Attributen zuständig sind, wie in der zweiten und dritten Operation des vorangestellten Beispiels. Bei der zweiten "update"-Operation handelt es sich, um eine Modifikation an einem Attribut, dessen Wertebereich in der Basistabelle durch einen Objekttypen festgelegt ist und nur das Unterattribute "strasse" modifiziert. Die Unterattribute müssen aufgrund der Struktur der Sicht alle einzeln modifiziert werden, da sie auch als einzelne Attribute und nicht als gesamtes Attribut selektiert worden sind. Deshalb muß bei der Konstruktion dieser "update"Operation darauf geachtet werden, daß der Pfad, durch den das Unterattribut in der Tabelle identifiziert wird, korrekt aus den Komponenten Tupelvariable, Objekttypname und Unterattributname zusammengesetzt wird. Bei der dritten "update"-Operation handelt es sich, um eine Modifikation an einem Attribut, dessen Wertebereich durch einen Fremdschlüssel auf eine Tabelle festgelegt ist, die eine Werteklasse repräsentiert. Hier besteht wieder das Problem, daß eine gültige "vid" aus der Tabelle "vc_abteilung" selektiert werden muß, um die "Update"-Operation korrekt durchführen zu können. Ansonsten wird gegen die Integritätsbedingungen des Fremdschlüssels verstoßen. Dieses Problem wird durch die Formulierung einer "Select"-Operation gelöst, welche die benötigte "vid" aus der Tabelle selektiert und dem Attribut 87 Inhaltsverzeichnis "abteilung" in der Tabelle "oc_angestellter" als Wert in dem Tupel zugewiesen wird, welches durch die "oid" des Tupels in der Sicht "angestellter" eindeutig identifiziert wird. Die Konstruktion des Instead-of-Delete-Triggers ist im Vergleich zu den bereits vorgestellten Instead-of-Triggern relativ einfach. Da auch dieser Triggertyp ein "row-level"-Trigger ist, wird er für jedes Tupel, das von der "delete"-Operation in der Sicht betroffen ist, einmal ausgelöst. Der Instead-of-Delete-Trigger enthält genauso viele "delete"-Operationen, wie Basistabellen an der Konstruktion seiner Sicht beteiligt sind. Die einzige Bedingung in der Bedingungsklausel der "delete"-Operation, besteht darin, daß der Wert des Attributs "oid" in den Basistabellen identisch zu dem Wert des Attributs "oid" in der Sicht sein. CREATE OR REPLACE TRIGGER student_delete INSTEAD OF DELETE ON student BEGIN DELETE FROM oc_person WHERE oid = :old.oid; DELETE FROM oc_angestellter WHERE oid = :old.oid; DELETE FROM oc_student WHERE oid = :old.oid; END; Beispiel 6.4.3: Instead-of-Delete-Trigger der Sicht Student An der Definition der Sicht Student sind die drei Basistabellen "oc_person", "oc_angestellter" und "oc_student" mit ihren Attributen beteiligt. Aus diesem Grund wird in dem Trigger "student_delete" im Beispiel 6.4.3 jeweils eine "delete"-Operation an diese Tabellen gerichtet, um alle Daten zu löschen, die einer Instanz der Objektklasse "student" entsprechen. Michael Horn 6.4.4 Abgeleitete Objektklassen Abgeleitete Objektklassen werden durch eine Klassendefinition definiert und durch eine Populationsregel mit Daten gefüllt. Es ist nicht möglich neue Objekte für eine abgeleitete Klasse direkt zu erzeugen oder bereits bestehende Objekte zu verändern. Daher werden durch die Übersetzung abgeleiteter Chimera-Objektklassen nach Oracle-SQL keinerlei Trigger zur Datenmanipulation erzeugt. Wie in Kapitel 2 bereits erläutert, entsprechen abgeleitete Objektklassen in Chimera den Sichten der relationalen Datenmodells. Sichten im relationalen Modell werden durch Anfragen an die Datenbank definiert. Dieses Vorgehen entspricht der Kombination aus Klassendefinition und Populationsregeln. Die Klassendefinition legt die zu selektierenden Spalten und die Populationsregel die Datenherkunft und die Bedingungen fest. Durch folgende Definition "abgestellter" definiert: wird eine abgeleitete Unterklasse der Objektklasse 88 Inhaltsverzeichnis define object class edv derived superclasses angestellter end; define implementation for edv population edv(E) <angestellter(E), E.abteilung.bereich = "EDV" end; Basierend auf der in Kapitel 7 beschriebenen Übersetzung deklarativer Ausdrücke, würde obiges Beispiel in folgende relationale Sicht übersetzt: CREATE VIEW edv AS SELECT * FROM angestellter E, abteilung abteilung_1 WHERE E.abteilung = abteilung_1.vid AND abteilung_1.bereich = 'EDV' Durch den verwendeten Pfadausdruck in der Definition der Populationsregel der abgeleiteten Objektklasse "edv" muß der View basierend auf zwei Tabellen definiert werden. Obiger View würde alle Objekte der Klasse "angestellter" beinhalten, deren Abteilung dem Bereich "EDV" zugeordnet wurde. Abgeleitete Objektklassen dürfen nur abgeleitete Unterklassen besitzen. Das einfachste Vorgehen für die Übersetzung abgeleiteter Klassenhierarchien besteht darin, die Sicht der Oberklasse als Basis für die Definition einer neuen Sicht zu verwenden und die Populationsregel als Bedingung für die neue Sicht zu übernehmen. Folgendes Beispiel definiert eine abgeleitete Unterklasse für die Klasse "EDV". define object class teure_edv derived superclasses edv end; define implementation for teure_edv population teure_edv(T) <- edv(T), T.gehalt > 200000 end; 89 Inhaltsverzeichnis Basierend auf obigen Vorgehen, würde die abgeleitete Unterklasse wie folgt nach SQL übersetzt: CREATE VIEW teure_edv AS SELECT * FROM edv T WHERE T.gehalt > 200000 Die momentane Implementierung basiert auf obigem Verfahren. Dieses Verfahren ist allerdings nicht sehr effizient, sobald Anfragen an eine Sicht formuliert werden müssen. Zur Beantwortung einer Anfrage auf einer Unterklasse einer abgeleiteten Klasse muß zuerst die Population der Oberklasse berechnet werden um im Nachhinein die Population der benötigten Unterklasse zu berechnen. Dieses Art der Definition von Sichten basierend auf anderen Sichten kann vom SQL-Optimierer des Oracle-Datenbankservers nicht effizient ausgewertet werden, da der Optimierer davon ausgeht, das Sichten nur basierend auf Tabellen definiert werden. Daher werden bei der Optimierung die zusätzlichen Informationen der verwendeten Sichten nicht mit verarbeitet. Durch eine Analyse aller Populationsregeln der abgeleiteten Klassenhierarchie kann dieses ineffiziente Vorgehen optimiert werden. Bei genauerer Untersuchung der beiden obigen Populationsregeln stellt man fest, daß die Populationsregel der abgeleiteten Klasse "teure_edv" die Population der abgeleiteten Objektklasse "edv" weiter einschränkt. Die deklarativen Ausdrücke, die innerhalb einer Populationsregel verwendet werden, können in zwei unterschiedliche Gruppen unterteilt werden: 1. deklarative Ausdrücke, die die Objektherkunft beschreiben 2. deklarative Ausdrücke, die Bedingungen für die Objekte formulieren Werden nun die Populationsregeln der zu definierenden Klasse mit denen aller abgeleiteten Oberklassen kombiniert, so entsteht eine einzige Regel, die nur auf extensionalen Objektklassen basiert. Bei der Kombination der Regeln können die Klassenformeln, die die Daten der jeweiligen Oberklasse selektieren, gelöscht werden. Die durch die gelöschten Klassenformeln definierten Variablen werden durch die entsprechenden Variablen der Populationsregel der Oberklasse ersetzt. Für obiges Beispiel bedeutet dies, daß die Populationsregel für die abgeleitete Unterklasse "teure_edv" wie folgt aussehen könnte: define implementation for teure_edv population teure_edv(E) <- angestellter(E), E.abteilung.bereich = "EDV", E.gehalt > 200000 end; 90 Inhaltsverzeichnis Die Übersetzung obiger Regel nach Oracle-SQL würde folgende Sicht definieren CREATE VIEW teure_edv AS SELECT * FROM angestellter E, abteilung abteilung_1 WHERE E.abteilung = abteilung_1.vid AND abteilung_1.bereich = 'EDV' AND E.gehalt > 200000 Die Definition der obigen Sicht kann effizienter abgearbeitet werden, da sie nur auf Tabellen basiert. Die durch die Klassenformel "edv(T)" definierte Variable "T" ist durch die entsprechende Variable "E" aus der Definition der Populationsregel der Klasse "edv" ersetzt worden. Andrea Scheuber 6.5 Vergleich zum CPTPhx-Ansatz Bei der Übersetzung eines Chimera-Schemas nach Phönix wird für jede Objektklasse des Schemas eine extensionale Relation und eine dazugehörige abgeleitete Relation angelegt. Jede Phoenix-Relation besitzt eine OID-Spalte, in welcher der Objektidentifikator des jeweiligen Datensatzes gespeichert wird. In jeder Relation werden Spalten für jedes Attribut eines Chimera-Objektes angelegt. Dies bedeutet, daß im folgenden Beispiel die Relation Student, zusätzlich zu ihren eigenen Attributen, auch noch alle Attribute ihrer Oberklasse Person bekommt. Dadurch wird ein einfacher Zugriff auf jeden Datensatz einer Relation gewährleistet. Wird nun eine Anfrage an die Oberklasse "person" gestellt, werden die Daten aus der Relation "person" und die Daten aus der Relation "student" in einer Sicht zusammengeführt und repräsentieren somit die gesamten Daten der Objektklasse "person". Auf diese Weise müssen die Daten nicht doppelt in den Relationen abgelegt werden, was in Bezug auf den Verbrauch des Speicherplatzes ineffizient wäre. Die Daten einer Oberklasse müssen also erst in Form von Sichten berechnet werden, bevor sie weiter verwendet werden können. Dafür kann auf die Daten der am meisten spezifizierten Klassen direkt zugegriffen werden. 91 Inhaltsverzeichnis Chimera Person Phönix Person Name String OID Integer Vorname String Name String Vorname String Ï Student Matrikel_nr Ï Student Integer OID Integer Name String Vorname String Matrikel_nr Integer Abbildung 6.1: Übersetzung einer Chimera-Klassenhierarchie nach Phönix Auf den ersten Blick ähneln sich die beiden Ansätze zur Implementation von Chimera auf der Basis der beiden Datenbanksystem Phoenix (CPTPhx) und Oracle (CPTOracle) einander. Beide Ansätze benutzen die Konzepte von extensionalen Relationen (Tabellen) in Kombination mit abgeleiteten Relationen (Sichten). Tatsächlich aber unterscheiden sie sich in wesentlichen Punkten voneinander, was die Organisation von Daten und ihrer Berechnung anbelangt. Das CPTPhx ist so realisiert, daß ein direkter und effizienter Zugriff auf die Attribute der am meisten spezialisierte Klasse (most specific class) ermöglicht wird. Dieser Ansatz führt dazu, daß die Daten aller übergeordneten Oberklassen über Sichten berechnet werden müssen, um die kompletten Daten einer Oberklasse zu erhalten. Dieser Ansatz wurde gewählt, um effizient die Daten einer spezialisierten Klasse zu bearbeiten, da man davon ausgeht, daß mit diesen auch hauptsächlich gearbeitet wird. Ein große Nachteil dieser Vorgehensweise ist, daß bei der Berechnung der Daten der am wenigsten spezialisierten Klassen (least specific class) einer Klassenhierarchie eine ganze Kette von Berechnungen der Sichten aller spezialisierteren Klassen, die untereinander in Verbindung stehen, ausgelöst wird. Die Implementation von CPTOracle bietet durch das gewählte Konzept einen direkten und effizienten Zugriff auf die Attribute der am wenigsten spezialisierte Klasse. Die Daten aller Anfragen an spezialisiertere Klassen werden über die Spezifikation der jeweiligen Sicht berechnet. Da die Sichten immer auf Tabellen und nicht, wie im CPTPhx, auch auf anderen Sichten aufbauen, muß nur eine Sicht berechnet werden. Der Ansatz dieser Übersetzung geht von folgender Annahme über das Datenaufkommen in den Relationen aus: Die größte Datenmenge ist für die am wenigsten spezialisierte Klasse einer Klassenhierarchie zu erwarten, da alle Instanzen einer spezialisierten Klasse ebenfalls Instanzen ihrer Oberklassen sind. Daher haben wir uns für einen schnelleren Zugriff auf die größere Datenmenge entschieden. 92 Inhaltsverzeichnis Einen großen Vorteil bietet Oracle gegenüber Phoenix im Zusammenhang mit Attributen und Nullwerten. Unter Phoenix ist es nicht möglich, einem Attribut keinen Wert bzw. den Wert "null" zuzuweisen. Das bedeutet, daß allen Attribute immer ein gültiger Wert zugewiesen werden muß. Dadurch ist die Integritätsbedingung "notnull", die Bestandteil der Sprachspezifikation von Chimera ist, nicht in CPTPhx realisiert, da Phoenix grundsätzlich keine Nullwerte bei Built-in-Datentypen unterstützt. Damit ist die Umsetzung dieses Integritätsbedingungstyps überflüssig. In Oracle ist es möglich, jedem beliebigen Built-in-Datentyp den Wert "null" zuzuweisen. Dies ist nützlich, wenn im ersten Schritt ein Datensatz mit nur teilweise bekannten Daten generiert werden soll. Im zweiten Schritt kann dieser Datensatz mit neuen Daten vervollständigt werden. Diese Vorgehensweise ist benutzerfreundlicher, da nicht unbedingt alle erforderlichen Daten auf einmal zur Verfügung stehen können. Aus diesem Grund ist die Übersetzung der Bedingung "notnull" nach Oracle erforderlich, die durch die Built-in-Bedingung "not null" von Oracle einfach realisiert werden kann. Der große Vorteil von Phoenix liegt in der Vereinigung der imperativen, deduktiven und aktiven Elementen einer Programmiersprache. Dadurch ist es in Phoenix wesentlich einfacher, die Chimera-Konzepte der Integritätsbedingungen und Trigger umzusetzen, da Oracle deduktive und aktive Konzepte nur stark eingeschränkt in Form von Sichten und Triggern zur Verfügung stellt. Die Umsetzung von Triggern und Integritätsbedingungen erfolgt durch die Spezifikation von aktiven Regeln, die durch spezifizierte Ereignisse implizit ausgelöst werden. Beide Ansätze zur Implementierung von Chimera haben je nach Schemadefinition und Datenaufkommen Vor- und Nachteile. Eine optimale Lösung kann es bei beiden nicht geben, da sowohl Phoenix als auch Oracle hauptsächlich relationale Datenbanksysteme sind, welche die objektorientierten Konzepte von Chimera nicht eins zu eins umsetzen können, sondern sie durch relationale Konzepte simulieren müssen und dadurch keine optimale und vollständige Umsetzung erreichen können. 6.6 Unterschiede zwischen CPTPhx und CPTOracle Basierend auf dem momentanen Stand der Implementation, existieren folgende zusätzliche Einschränkungen: • Der Chimera-Datentyp "string" wird nur mit Längenbeschränkungen bei der Übersetzung eines Schemas akzeptiert. • Der Chimera-Datentyp "real" wird durch den Wertebereich "number(10,10)" umgesetzt. Dies bedeutet, daß nur ein Ausschnitt des Wertebereichs von "real" unterstützt wird. 93 Inhaltsverzeichnis Michael Horn 7 Übersetzung deklarativer Ausdrücke Dieses Kapitel behandelt die Übersetzung deklarativer Chimera-Ausdrücke nach Oracle-SQL. Deklarative Ausdrücke finden Verwendung bei der Definition von Klassenpopulationsregeln und Attributherleitungsregeln, bei der Definition von Sichten, Integritätsbedingungen, Triggern und Operationen und bei der Formulierung von Anfragen an die Datenbank (siehe Kapitel 2). Trotz der unterschiedlichen Anwendung deklarativer Ausdrücke werden die einzelnen Konzepte immer auf die gleiche Art und Weise übersetzt. Der folgende Abschnitt beschäftigt sich mit der Übersetzung der einzelnen Konzepte deklarativer Ausdrücke. Abschnitt 7.2 wird auf besondere Aspekte der Implementierung eingehen. Der vorletzte Abschnitt dieses Kapitels wird angedachte Modifikationen und Optimierungen der Übersetzung vorstellen. Im letzten Abschnitt werden die Einschränkungen bzw. die Erweiterungen der Implementation basierend auf Oracle zur bisher bestehenden Implementierung des CPT zusammengefaßt. Alle Beispiele im folgenden Kapitel basieren auf der Klassenhierarchie, die in Kapitel 2 während der Vorstellung der Schemakonzepte eines Chimera-Schemas definiert wurde. 7.1 Konzepte der Übersetzung deklarativer Ausdrücke nach SQL Deklarative Ausdrücke werden zur Definition von Bedingungen einer Selektion benutzt. Die Verwendung der Ergebnisse einer Anfrage an eine Chimera-Datenbank wird durch den Kontext der Anfrage definiert. SQL bietet nur eine Möglichkeit, Selektionen zu formulieren: "select"-Anweisungen. Eine SQL-"select"-Anweisung besteht aus drei unterschiedlichen Hauptteilen: 94 Inhaltsverzeichnis • "select": In diesem Teil werden die Spalten definiert, die durch diese Operation angezeigt werden sollen. • "from": Dieser Teil legt die Tabellen und Sichten fest, aus den die Daten selektiert werden sollen. • "where": In diesem Teil können beliebige Bedingungen formuliert werden, die die anzuzeigenden Daten erfüllen müssen, u. a. können auch Tabellen über sogenannte "join"Bedingungen miteinander verknüpft werden. Die weiteren Optionen und Möglichkeiten der "select"-Operation werden für die Übersetzung deklarativer Ausdrücke nicht benötigt. Die einzelnen Konzepte deklarativer Ausdrücke werden auf die "from"- und "where"-Teile der "select"-Anweisung übersetzt. Die genaue Auswahl der zu selektierenden Spalten hängt vom Kontext des deklarativen Ausdrucks ab und ist Thema der Schemaübersetzung (Kapitel 6) und der Übersetzung imperativer Ausdrücke (Kapitel 8). Deklarative Ausdrücke in Chimera können Kombinationen von mehreren Ausdrücken sein, die mittels Konjunktion zu einem Ausdruck zusammengefaßt werden. Innerhalb einer "select"-Anweisung lassen sich Konjunktionen auf zwei unterschiedliche Arten ausdrükken. Mehrere Bedingungen innerhalb eines "where"-Teils einer "select"-Anweisung können durch das Schlüsselwort "AND" (Konjunktion) zusammengefaßt werden. Die Verwendung mehrere Tabellen oder Sichten innerhalb eines "from"-Abschnittes einer "select"-Anweisung werden durch ein Komma (",") voneinander getrennt. Die Verwendung des Kommas bewirkt, daß über alle verwendeten Tabellen und Sichten das kartesische Produkt gebildet wird. Das kartesische Produkt ist in diesem Fall ein Spezialfall der Konjunktion. Bei der Berechnung des kartesischen Produktes werden eventuelle Einschränkungen des "where"-Teils einer Anfrage beachtet. Durch diese Optimierung wird der Berechnungsaufwand stark reduziert. Der "from"-Abschnitt einer Anfrage legt alle Tabellen und Sichten fest, aus denen die gewünschten Daten stammen sollen. Es ist nicht möglich mittels Negation das Gegenteil zu fordern, daß die Daten nicht aus dieser Tabelle oder Sicht stammen dürfen. Negation kann nur in "where"-Teil einer Anfrage verwendet werden. Das Vorgehen in SQL ist also, eine Tabelle im "from"-Abschnitt einer Anweisung zu verwenden und die Werte dann durch entsprechende Bedingungen im "where"-Teil auszuschließen. Eine zweite Möglichkeit besteht darin, im "where"-Teil einer Anfrage eine Unteranfrage zu formulieren und deren Werte dann anschließend Mittels Negation auszuschließen (siehe Übersetzungen von Mitgliedsformeln). Die in Kapitel 2.3 eingeführten Klassenformeln legen den Wertebereich für die an die jeweilige Objektklasse gebundene Variable fest. Der "from"-Teil einer SQL "select"Anweisung erfüllt eine ähnliche Aufgabe: Er bietet die Möglichkeit, eine selbstdefinierte Variable für eine verwendete Tabelle oder Sicht zu definieren. Diese Variable entspricht einer Tupelvariable. Jedes Tupel einer relationalen Datenbank wird durch einen eindeutigen Tupelidentifikator bezeichnet. Im Kontext von Oracle heißt der Tupelidentifikator "row number". Die Bedeutung einer Chimera-Objektvariable und einer SQL-Tupelvariable entsprechen sich weitgehend. Da im Falle der Übersetzung eines Chimera-Schemas in ein Oracle-SQL-Schema nur Sichten durch deklarative Ausdrücke selektiert werden, ist die Bedeutung der Tupelvaria95 Inhaltsverzeichnis ble einer Sicht identisch zu Bedeutung einer Objektvariable in Chimera. Ein Datensatz einer Sicht entspricht immer einem kompletten Chimera-Objekt. deklarativer Ausdruck in Chimera Übersetzung nach Oracle-SQL person(X), student(Y) select ... from person X, student Y where ... Obiges Beispiel verdeutlicht, wie Klassenformeln in den "from"-Teil einer "select"Anweisung übersetzt werden. Würde obiger deklarativer Ausdruck in einem Chimera "select"- oder "display"-Befehl verwendet um Attribute der beiden Klassen zu selektieren, so würde ebenfalls das kartesische Produkt gebildet werden. Vergleichsformeln von Chimera und SQL unterscheiden sich nur in einem kleinen Detail: Die Zeichenkette für Ungleichheit in Chimera ("\=") entspricht der "!="-Zeichenkette von Oracle SQL. Alle anderen Vergleichsoperatoren werden ohne Veränderung übernommen. Vergleichsformeln deklarativer Ausdrücke definieren Bedingungen, die in den "where"Teil einer "select"-Anweisung überführt werden. deklarativer Ausdruck in Chimera Übersetzung nach Oracle-SQL person(X), X.name = "Horn" select ... from person X where X.name = 'Horn' Obiges Beispiel zeigt eine weitere Besonderheit der Übersetzung auf. Zeichenketten werden in Chimera durch doppelte Anführungszeichen (") gekennzeichnet. Der SQL-Dialekt von Oracle fordert dagegen ein einfaches Anführungszeichen (') zur Kennzeichnung von Zeichenketten. Obiges Beispiel zeigt, daß die Tupelvariablen einer Oracle-Tabelle die gleiche Funktionalität bzgl. des Zugriffs auf Attribute, wie die Objektvariablen von Chimera besitzen. Vergleichsformeln können auch Pfadausdrücke verwenden. Diese Ausdrücke können schon auf der Seite von Chimera in eine Kombination aus Klassen- und Vergleichsformeln aufgespalten werden. person(X), X.adresse.ort = "Meckenheim" Î person(X), adresse(Y), X.adresse = Y, Y.ort = "Meckenheim" Das obige Beispiel zeigt den Vorgang der Normalisierung deklarativer Ausdrücke. Der normalisierte Ausdruck wird anschließend in die entsprechende Kombination der "from"- und "where"- Teile einer "select"-Anweisung übersetzt: 96 Inhaltsverzeichnis deklarativer Ausdruck in Chimera Übersetzung nach Oracle-SQL person(X), adresse(Y), X.adresse = Y, Y.ort = "Meckenheim" select from where and ... person X, adresse Y X.adresse = Y.oid Y.ort = "Meckenheim" Obiges Beispiel zeigt noch eine Besonderheit der Übersetzung: Das Attribut "adresse" der Objektklasse "person" ist ein objektwertiges Attribut. Die Objektidentifikatoren werden in den durch die Schemaübersetzung generierten "oid"-Spalten gespeichert. Daher muß im obigen Vergleich, das Attribut "adresse" mit der "oid"-Spalte der Sicht "adresse" gleichgesetzt werden. Das letzte Basiskonzept deklarativer Ausdrücke in Chimera sind die Mitgliedsformeln. Mitgliedsformeln können in drei unterschiedliche Klassen unterteilt werden: • Mitgliedsformeln für Objektklassen • Mitgliedsformeln für Wertetypen und –klassen • Mitgliedsformeln für Listen und Mengen Alle drei Arten überprüfen, ob der Wert einer Chimera-Variable oder eines Attributes in einem Wertebereich liegt. Im ersten Fall entspricht der Wertebereich der Menge der Objektidentifikatoren der Objektklasse, im zweiten Fall dem Wertebereich der Datentypen und im dritten Fall den Elementen der Liste oder Menge. deklarativer Ausdruck in Chimera Übersetzung nach Oracle-SQL person(X), X in student select ... from person X where X.oid IN select oid from oc_student Mitgliedsformeln für Objektklassen werden durch eine Unteranfrage an die zur Mitgliedsformel gehörende Objektklasse übersetzt. Der Objektidentifikator der Objektklasse wird selektiert und mit dem Wert der Variable verglichen. Durch diese Übersetzung werden im obigen Beispiel nur Objekte von "person" selektiert, die ebenfalls Studenten sind. Bei obiger Übersetzung ist zu beachten, daß hier von der Tabelle "oc_student" die Objektidentifikatoren selektiert werden (siehe Kapitel 6). Alle bisher vorgestellten Übersetzungen basierten immer auf den Oracle-Sichten, die die Chimera-Klassenhierarchie repräsentieren. In diesem Fall kann allerdings der Zugriff auf die Sicht "student" umgangen werden, da nur die Objektidentifikatoren der Studenten interessant sind. Die Objektidentifikatoren werden in der "oid"-Spalte der Tabelle "oc_student" verwaltet. Durch dieses Wissen werden die zur Berechnung der Sicht "student" benötigten Joins eingespart und die Anfrage kann effizienter ausgewertet werden. 97 Inhaltsverzeichnis 7.2 Implementierung Der folgende Abschnitt dokumentiert das implementierte Verfahren zur Übersetzung von deklarativen Ausdrücken nach Oracle SQL. Es werden dabei einige Besonderheiten aufgezeigt, die Aufgrund von Problemen während der Implementation gelöst werden mußten. Alle Prolog-Prädikate, die zur Vorbereitung der Übersetzung und zur Übersetzung von deklarativen Ausdrücken benötigt werden, sind im Modul dec2oracle definiert. Jede Übersetzung eines deklarativen Ausdrucks läßt sich in folgende Phasen unterteilen: 1. alle Chimera-Variablen werden durch generierte Platzhalter ersetzt 2. alle Pfadausdrücke werden aufgelöst 3. der resultierende deklarative Ausdruck wird übersetzt 4. interne Informationen bzgl. der verwendeten Variablen werden gelöscht Als Ergebnis der Übersetzung wird der generierte "from"- und "where"-Ausdruck in Form einer Zeichenkette an den Aufrufer zurückgegeben. Die Schlüsselworte "from" und "where" sind in den Rückgabewerten noch nicht enthalten, da bei der Übersetzung des Kontextes eines deklarativen Ausdrucks weitere Bedingungen entstehen können (siehe Kapitel 8). Jede Stelle, die mit deklarativen Ausdrücken umgehen muß, muß obige vier Schritte separat durchführen. Dieses Vorgehen ist nötig, da z.B. Variablen, die in einem deklarativen Ausdruck definiert werden, in einer kompletten Transaktionszeile verwendet werden können. Die Auflösung der Pfadausdrücke wird ebenfalls sowohl innerhalb von deklarativen Ausdrükken aber auch zur Übersetzung von Anfragen an die Datenbank benötigt. Die Funktionsweise der Übersetzung wird anhand folgender Anfrage erläutert: display( X.name, X.adresse.ort where person(X), X in student, X.name = "Horn" ); Alle Prädikate der Übersetzung deklarativer Ausdrücke erwarten als Eingabe eine Listen von Zeichenketten. Alle DDL- und DML-Befehle an eine Chimera-Datenbank werden durch die bestehenden Prädikate des CPTPhx in die benötigte Liste überführt. Die DML-Schnittstelle des CPT übersetzt obige Anfrage in folgende Liste: [ display, "(", var(X), ".", name, ",", var(X), ".", adresse, ".", ort, where, person, "(", var(X), ")", ",", var(X), in, student, ",", var(X), ".", name, "=", "Horn", ")" ] Der erste Schritt der Übersetzung deklarativer Ausdrücke ist die Generierung von Platzhaltern für verwendete Variablen. Dieses Vorgehen ist nötig, da es während der Implementation nicht gelungen ist, an den Namen einer verwendeten Variable zu gelangen. Variablen, im obigen Beispiel das X, werden durch die DDL- und DML-Schnittstelle des CPT in PrologCompounds übersetzt. ECLiPSe stellt für die Extraktion einer Variable aus einem Compound 98 Inhaltsverzeichnis die Operation "::-" zur Verfügung. Anschließend kann mit Hilfe des Prädikates "get_var_info/3" der Name einer Variable ermittelt werden. Der Name wird in Form einer Zeichenkette ausgegeben. Das Vorgehen scheitert allerdings aus nicht ermittelbaren Gründen, wenn die entsprechenden Prädikate in einem laufenden CPT-System verwendet werden; ein laufendes ECLiPSe ohne das CPT liefert dagegen immer den gewünschten Namen der verwendeten Variable. Obiges Problem wurde durch die automatische Generierung von Platzhaltern gelöst. Alle in der Liste auftauchenden Compounds werden durch eine fortlaufende Nummer mit Präfix "var_" ersetzt. Die Ersetzungen werden durch ein Prädikat in der Prolog-Datenbank protokolliert: Das Prolog-Prädikat "varName/2" speichert sowohl die verwendete ChimeraVariable als auch den generierten Platzhalter. Für jede Klassenformel wird zusätzlich der Platzhalter sowie der Klassenname durch das Prädikat "varInfo/2" gespeichert. Jedes Auftreten einer Variable wird durch den identischen Platzhalter ersetzt. Das Ergebnis der Variablenersetzung für obiges Beispiel sieht wie folgt aus: [ display, "(", var_1, ".", name, ",", var_1, ".", adresse, ".", ort, where, person, "(", var_1, ")", ",", var_1, in, student, ",", var_1, ".", name, "=", "Horn", ")" ] In den beiden Prolog-Relationen "varName/2" und "varInfo/2" werden demnach folgende Fakten gespeichert: varName/2 varInfo/2 varName( var(X), var_1 ) varInfo( person, var_1 ) Der zweite Schritt während der Übersetzung ist die Eliminierung sämtlicher Pfadausdrücke eines Chimera-Befehls. Da Oracle-SQL nicht in der Lage ist, Pfade automatisch zu verarbeiten, müssen Pfadausdrücke aus den Chimera-Befehlen entfernt werden. Das Prädikat "expandPath/2" durchläuft eine Liste von Zeichenketten und entfernt alle Pfadausdrücke. Dabei werden zwei aufeinanderfolgende Anwendungen der Attributfunktion durch eine ersetzt. Die entfernte Anwendung der Attributfunktion wird durch eine neue Variable, eine Klassenformel und eine Gleichung ersetzt. Obiger Pfadausdruck wird demnach wie folgt ersetzt: var_1.adresse.ort Î adresse_1.ort where adresse( adresse_1 ), var_1.ort = adresse_1.oid Die neue Variable wird durch den Namen der dazugehörigen Klasse und einer fortlaufenden Nummer benannt. Die betroffene Klasse kann basierend auf den Informationen für den Platzhalter "var_1" und den Informationen des Chimera Data Dictionary (CDD) ermittelt werden. Die zusätzlichen Bedingungen werden nach Durchlaufen der kompletten Liste am Ende der Liste angehängt: 99 Inhaltsverzeichnis [ display, "(", var_1, ".", name, ",", adresse_1, ".", ort, where, person, "(", var_1, ")", ",", var_1, in, student, ",", var_1, ".", name, "=", "Horn", ",", adresse, "(", adresse_1, ")", ",", var_1, ".", ort, "=", adresse_1,")"] Durch die neue Variable ergibt sich folgende Veränderung in den beiden Relationen: varName/2 varInfo/2 varName( var(X), var_1 ) varInfo( person, var_1 ) varInfo( adresse, adresse_1 ) Im obigen Beispiel wird nun die Liste der Zeichenketten geteilt. Alle Elemente der Liste, die auf der linken Seite des Schlüsselwortes "where" stehen werden durch die Übersetzung der Datenmanipulationsbefehle bearbeitet (siehe Kapitel 8). Alle Elemente auf der rechten Seite des Schlüsselwortes stellen einen deklarativen Ausdruck dar und werden durch das Prädikat "translateDecExp/3" in den "from"- und "where"-Teil einer SQL-Anweisung übersetzt. Das Vorgehen der eigentlichen Übersetzung ist folgendes: Die Liste der Zeichenketten wird von links nach rechts abgearbeitet. Jedes Konzept eines deklarativen Ausdrucks hat eine eindeutige Signatur Anhand deren man das entsprechende Konzept eindeutig identifizieren kann. Zur Identifikation eines Konzeptes müssen nur unterschiedlich viele Elemente der Liste der Zeichenkette im voraus gelesen werden: • Klassenformeln bestehen immer aus vier Teilen: einer Zeichenkette, einer geöffneten, runden Klammer, einer Variablen und einer geschlossenen, runden Klammer. • Mitgliedsformeln bestehen aus unterschiedlich vielen Teilen, in denen aber immer das Schlüsselwort "in" auftauchen muß. • Vergleichsformeln bestehen ebenfalls aus unterschiedlich vielen Teilen, in denen aber immer genau ein Vergleichssymbol verwendet werden muß. Anhand der jeweilige eindeutigen Signatur können die entsprechenden Konzepte dann Schritt für Schritt in entsprechende Teile einer SQL-"select"-Anweisung übersetzt werden. Obiges Beispiel wird durch das Prolog-Prädikat in folgende "from"- und "where"-Teile übersetzt. Das Prädikat wird folgende beiden Zeichenketten als Rückgabewert liefern. Eingabe: [ person, "(", var_1, ")", ",", var_1, in, student, ",", var_1, ".", name, "=", "Horn", ",", adresse, "(", adresse_1, ")", ",", var_1, ".", ort, "=", adresse_1, ")" ] Ausgabe FROM: person var_1, adresse adresse_1 Ausgabe WHERE: var_1.name = "Horn" AND var_1.ort = adresse_1.oid AND var_1.oid IN (SELECT oid FROM oc_student) 100 Inhaltsverzeichnis 7.3 Modifikationen und Optimierungen Die bisherige Implementation ist in keiner Weise optimiert, sie basiert auf der einfachsten Art und Weise für die Übersetzung. Sie könnte durch folgende Modifikationen und Optimierungen erweitert werden: • Das Entfernen von Pfadausdrücken und die eigentliche Übersetzung können parallel durchgeführt werden. • Durch die Analyse der verwendeten Klassen- und Mitgliedsformeln kann die am meisten spezialisierende Objektklasse ermittelt werden. Durch diese Analyse können Joins verhindert werden. • Bisher basieren die Anfragen auf den Sichten, die die Chimera-Klassenhierarchie repräsentieren. Es ist möglich, die Anfragen direkt auf den Tabellen zu beantworten und die Joins manuell durchzuführen. • Durch eine Analyse der selektierten Attribute der Anfragen und in der Definition von abgeleiteten Objektklassen, Sichten, Integritätsbedingungen und Trigger können überflüssige Joins vermieden werden. Die erste Optimierung der Übersetzung ist leicht einzusehen. Das Entfernen von Pfadausdrücken ersetzt Elemente der Liste durch andere Elemente und fügt neue Elemente der Liste hinzu. Den Vorgang des Ersetzens muß nicht verändert wer, die hinzugefügten Elemente der Liste können allerdings direkt in die entsprechenden "from"- und "where"-Teile eines "select"-Befehls übersetzt werden. Der erste Schritt der Analyse der vorhanden ChimeraVariablen und deren Ersetzung durch Platzhalter könnte ebenfalls parallel ausgeführt werden. Während der Ersetzung der Variablen durch Platzhalter werden allerdings die Informationen der verwendeten Klassenformeln gesammelt und in dem Prädikat "varInfo/2" gespeichert. Da diese Informationen während des Entfernens von Pfaden innerhalb des Ausdrucks benötigt werden, muß dieser Schritt separat ausgeführt werden. Die Zeit, die zur Beantwortung einer Anfrage an eine Datenbank benötigt wird, hängt sehr stark von der Anzahl der zu bildenden kartesischen Produkte ab. Die Anzahl der kartesischen Produkte wiederum hängt von der Anzahl der Joins und der Anzahl der dadurch betroffenen Datensätze ab. Das Ziel einer Anfrageoptimierung sollte also die Reduzierung von Joins im Bedingungsteil einer Anfrage sein. Alle drei weiteren Optimierungen der bisherigen Übersetzung zielen auf die Reduzierung von Joins ab. Die erste Möglichkeit, die Anzahl der Joins zu vermindern liegt in der Analyse der verwendeten Klassen- und Mitgliedsformeln eines deklarativen Ausdrucks. Wie in Kapitel 2 beschrieben, definiert eine Klassenformel den Wertebereich einer Chimera-Variable, eine Mitgliedsformel schränkt den Wertebereich einer Variable zusätzlich ein. Basierend auf der in Kapitel 6 vorgestellten Übersetzung eines Chimera-Schemas in ein Oracle-SQL-Schema und der damit verbunden Übersetzung deklarativer Ausdrücke nach SQL können Anfragen immer, basierend auf der am meisten spezialisierten Objektklasse, beantwortet werden. Basierend auf dem Beispiel aus dem vorherigen Abschnitt bedeutet dies: Die Unteranfrage innerhalb des "where"-Abschnittes der Anweisung entfällt; die Anfrage würde nur über der Objektklasse "student", also nur indirekt über der Objektklasse "person", beantwortet 101 Inhaltsverzeichnis werden. Die Verbindung zwischen der Objektklasse "person" und der Objektklasse "student" wird durch die Oracle-Sicht "student" hergestellt: Eingabe: [ person, "(", var_1, ")", ",", var_1, in, student, ",", var_1, ".", name, "=", "Horn", ",", adresse, "(", adresse_1, ")", ",", var_1, ".", ort, "=", adresse_1, ")" ] Ausgabe FROM: student student_1, adresse adresse_1 Ausgabe WHERE: student_1.name = "Horn" AND student_1.ort = adresse_1.oid Jedes DBMS besitzt einen Optimierer für Anfragen an die Datenbanken. Der Optimierer definiert eine Abarbeitungsreihenfolge, in der die einzelnen Bedingungen einer Anfrage abgearbeitet werden sollen. Dies bedeutet, daß Joins z.B. nach der geschätzten Anzahl der zu erwartenden Datensätze sortiert werden. Bezogen auf Joins bedeutet dies, daß zuerst "billige" Joins abgearbeitet und erst gegen Ende der Anfragebeantwortung die "teuren" Joins durchgeführt werden. (Die Klassifizierung von Join-Operationen in "billige" und "teure" Joins, basiert auf der Abschätzung der zu erwartenden Datensätze in der Resultatmenge.) Die Ergebnisse des Oracle-Optimierers sind allerdings nicht immer optimal: Wie in Kapitel 6 vorgestellt, verzögert sich die Anfragebeantwortung rapide, sobald eine Oracle-Sicht basierend auf einer anderen Oracle-Sicht definiert wurde. Die Lösung der Schemaübersetzung ist, daß Sichten immer nur auf Tabellen basieren. Dieses Vorgehen kann auf die Übersetzung deklarativer Ausdrücke übertragen werden: Anstelle die Anfragen an die Sichten zu richten, wird die Anfrage basierend auf den Tabellen formuliert. Dies bedeutet das die Joins, die sonst durch die Sicht automatisch realisiert wurden, nun manuell in jedem Ausdruck durchgeführt werden müssen. Diese Verlängerung der Anfragedefinition führt zu einer vereinfachten Analyse der Anfrage, die zu besseren Laufzeitergebnissen führt. Obiges Beispiel würde nach dieser Optimierung wie folgt übersetzt: Eingabe: [ person, "(", var_1, ")", ",", var_1, in, student, ",", var_1, ".", name, "=", "Horn", ",", adresse, "(", adresse_1, ")", ",", var_1, ".", ort, "=", adresse_1, ")" ] Ausgabe FROM: oc_person oc_person_1, oc_student oc_student_1, oc_adresse oc_adresse_1 Ausgabe WHERE: oc_person_1.name = "Horn" AND oc_person_1.ort = oc_adresse_1.oid AND oc_person_1.oid = oc_student_1.oid 102 Inhaltsverzeichnis 7.4 Unterschiede zwischen CPTPhx und CPTOracle Basierend auf dem momentanen Stand der Implementation existieren folgende zusätzliche Einschränkungen: • Klassenformeln für Datentypen werden nicht unterstützt: Dies bedeutet, daß es momentan nicht möglich ist, neue Variablen innerhalb eines deklarativen Ausdrucks zu definieren und durch eine Klassenformel den Wertebereich der Variable auf den Wertebereich eines Wertetyps oder einer Werteklasse einzuschränken. Dieses Problem wird für alle DMLOperationen und bei der Definition von Sichten auch weiterhin bestehen bleiben, da Standard-SQL keinerlei Möglichkeit bietet, Variablen zu definieren. Oracle bietet allerdings in der Definition von Operationen, Triggern und Integritätsbedingungen die Möglichkeit, neue Variablen zu definieren, da die Implementation dieser Konzepte auf Oracle PL/SQL basiert. • Mitgliedsformeln für Wertetypen und –klassen werden noch nicht unterstützt: Es ist momentan leider nicht möglich, die Zugehörigkeit des Wertes eines Attributes zu einem selbstdefinierten Wertetyp oder einer Werteklasse zu überprüfen, da diese Option noch nicht implementiert wurde. • Aggregats-, Mengen- und Listenfunktionen werden nicht unterstützt: Da die Implementierung des CPTOracle zum jetzigen Zeitpunkt noch keine Listen und Mengen unterstützt, werden die entsprechenden Funktionen für diese Konzepte auch noch nicht nach SQL übertragen. In späteren Erweiterungen müssen diese Funktionen deklarativer Ausdrücke noch nach SQL übersetzt werden. Die Implementierung dieser Funktionen wird stark von der gewählten Übersetzung der entsprechenden Schemakonzepte abhängen. 103 Inhaltsverzeichnis Andrea Scheuber 8 Übersetzung imperativer Ausdrücke Hinter dem Begriff der imperativen Ausdrücke (siehe Kapitel 2) verbergen sich zwei unterschiedliche Typen von Operationen, die über der Datenbasis des Datenbanksystems ausgeführt werden. Der erste Operationstyp sind die DML-Operationen, die für die Generierung und Pflege des Datenbestandes eingesetzt werden. Der zweite Operationstyp besteht aus den Anfragen, die an die Datenbank gestellt werden. Anfragen werden benutzt, um Daten zu selektieren, die entweder zur Formulierung von Bedingungen in DML-Operationen eingesetzt werden oder einfach nur ausgegeben werden. Die Reihenfolge der unterschiedlichen Operationen innerhalb einer Transaktion beeinflußt das Ergebnis einzelner Operationen, durch die am Ende einer Transaktion der neue Zustand der Datenbank bestimmt wird. Im Abschnitt 8.2 wird das Transaktionskonzept von Chimera vorgestellt und mit dem Transaktionskonzept von Oracle verglichen, bevor in den folgenden Abschnitten die Vorgehensweise zur Übersetzung der imperativen Ausdrücke von Chimera in imperative Ausdrücke von Oracle8-SQL vorgestellt wird. 8.1 Transaktionen Eine Transaktion ist eine Folge von Anfragen und DML-Operationen auf Datenbankobjekten. Die Reihenfolge, in der die einzelnen Operationen abgearbeitet werden, wird durch ihre Reihenfolge in der Transaktion bestimmt. Eine Transaktion wird als eine Einheit behandelt. Das bedeutet, wenn nur eine Operation einer Transaktion fehlschlägt, weil sie nicht zulässig ist, so werden die gesamten Änderungen, die innerhalb der Transaktion schon ausgeführt worden sind, zurückgesetzt und die Transaktion wird abgebrochen. Auf diese Weise wird die Erhaltung eines korrekten Datenbestandes gewährleistet. Die Überprüfungen, ob eine Operation zulässig ist, wird durch das DBMS des jeweiligen Datenbanksystems durchgeführt. Bei diesen Überprüfungen wird festgestellt, ob die Syntax der Operation korrekt ist und ob die Operationen gegen Integritätsbedingungen der Datenbank verstößt. Die Überprüfung von 104 Inhaltsverzeichnis Integritätsbedingungen ist immer an eine Transaktion gebunden, da sich die Datenbank spätestens nach Abschluß der Transaktion wieder in einem korrekten Zustand befinden muß. Die Überprüfung der Integritätsbedingungen kann zu zwei unterschiedlichen Zeitpunkten erfolgen. Entweder werden sie sofort nach der Ausführung der jeweiligen DML-Operation überprüft (engl. immediate constraint checking) oder aber erst am Ende der Transaktion, wenn alle Anfragen und Operationen abgearbeitet worden sind (engl. deferred constraint checking). Erst nachdem alle betroffenen Integritätsbedingungen überprüft worden sind und gewährleistet ist, daß sie nicht verletzt worden sind, kann eine Transaktion mit der Operation "commit" terminiert und die Änderungen in der Datenbank permanent verfügbar gemacht werden. Sobald festgestellt wird, daß eine Integritätsbedingung durch eine DML-Operation verletzt worden ist, wird die gesamte Transaktion durch die Operation "rollback" automatisch abgebrochen und alle schon durchgeführten, vorläufigen Änderungen am Datenbestand werden wieder zurückgesetzt. Eine Transaktion muß die folgenden vier Eigenschaften besitzen, damit sie zur Erhaltung eines korrekten Datenbestands beiträgt. Eine Transaktion ist atomar, da sie entweder als Einheit ausgeführt wird oder aber als Einheit fehlschlägt. Eine Transaktion führt ihre Operationen isoliert von anderen Transaktionen aus. Es darf keinerlei Verbindung mit anderen Transaktionen und deren Operationen bestehen. Eine Transaktion ist in sich konsistent. Das bedeutet, daß jeder Datenbankbestand, der durch eine korrekt abgeschlossene Transaktion zustande gekommen ist, auch ein gültiger Zustand ist. Die Änderungen, die durch eine abgeschlossene Transaktion zustande kommen, werden permanent im Datenbestand verfügbar gemacht, das bedeutet, daß keine dieser Änderungen verloren gehen darf. Sind diese Eigenschaften durch ein Transaktionskonzept umgesetzt, so ist auch die Korrektheit des Datenbestandes nach jeder Transaktion gewährleistet. 8.2 Das Transaktionskonzept von Chimera Ein Transaktion in Chimera beginnt immer mit dem Ausdruck "begin transaction", durch den der Anfang einer Transaktion gekennzeichnet wird. Wird dieser Ausdruck nicht explizit vor einer Folge von Operationen eingegeben, so wird implizit vor der erste Operation der Transaktion der Transaktionsanfang von Chimera markiert. Eine Transaktion wird in Chimera entweder mit dem Befehl "commit" abgeschlossen oder mit dem Befehl "rollback" zurückgesetzt, was bedeutet, daß alle Modifikationen, die innerhalb der aktuellen Transaktion vorgenommen worden sind, wieder rückgängig gemacht werden. Der Befehl "rollback" kann sowohl innerhalb der Transaktion explizit aufgerufen werden, als auch implizit durch Chimera ausgeführt werden. Die explizite Verwendung des Befehls "rollback" wird durch den Benutzer gesteuert, damit die Möglichkeit besteht, syntaktisch korrekte Operationen, die inkorrekte Daten enthalten, aber nicht von Chimera als solche erkannt werden können, zurückzusetzen. Die implizite Verwendung des Befehls "rollback" wird von Chimera im Zusammenhang mit der Überprüfung von Integritätsbedingungen gesteuert. Wird die Verletzung einer Integritätsbedingung vom Typ "immediate" festgestellt, so wird die gesamte Transaktion sofort nach der auslösenden Operation durch ein implizites "rollback" zurückgesetzt. Die Verletzung einer Integritätsbedingung vom Typ "deferred" wird erst am Ende einer Transaktion 105 Inhaltsverzeichnis festgestellt und deshalb kann erst dann von Chimera ein implizites "rollback" ausgelöst werden. Das Transaktionskonzept von Chimera sieht eine Unterteilung einer Transaktion in sogenannte Transaktionszeilen vor. Eine Transaktionszeile ist eine Folge von Operationen, die in direktem Zusammenhang zueinander stehen. Um eine Transaktion zu unterteilen, wird als Trennungszeichen zwischen zwei Transaktionszeilen ein Semikolon verwendet. Einzelne Operationen innerhalb einer Transaktionszeile werden jeweils durch ein Komma voneinander getrennt, um auf diese Weise zu kennzeichnen, daß sie Bestandteil der aktuellen Transaktionszeile sind. Der Sinn dieser Unterteilung einer Transaktion in logische Untereinheiten besteht darin, die Verwaltung von Variablenbindungen, die durch Anfragen an die Datenbank generiert und in DML-Operationen weiter verwendet werden, zu optimieren. Variablenbindungen existieren immer nur innerhalb der Transaktionszeile, in der sie auch erzeugt werden. Dadurch wird die Anzahl der Variablen und ihre assoziierten Werte möglichst gering gehalten. Wenn eine Transaktionszeile durch ein Semikolon abgeschlossen wird, hat dies die Löschung aller erzeugten Variablenbindungen zur Folge, die dann nicht mehr benötigt werden. Eine weitere Aufgabe von Transaktionszeilen besteht in der Festlegung des Ausführungszeitpunkts von Triggern. Im Chimera werden Trigger, wie auch Integritätsbedingungen, in zwei Typen unterschieden. Der erste Triggertyp beinhaltet die Trigger, welche sofort nach dem spezifizierten, auslösenden Ereignis ausgeführt werden müssen ("immediate"-Trigger). Der zweite Triggertyp umfaßt alle Trigger, die verzögert nach dem spezifizierten, auslösenden Ereignis am Ende einer Transaktion auszuführen sind ("deferred"-Trigger). Der Abschluß einer Transaktionszeile durch ein Semikolon definiert den Ausführungszeitpunkt der "immediate"-Trigger, die durch Operationen innerhalb der Transaktionszeile ausgelöst worden sind. Durch den Abschluß der gesamten Transaktion mit dem Befehl "commit", wird der Ausführungszeitpunkt, der "deferred"-Trigger definiert, die alle abgearbeitet werden, bevor das Datenbanksystem die Modifikationen am Datenbestand permanent übernimmt. Die Implementation von Chimera durch das CPTPhx setzt das Chimera-Transaktionskonzept um. Dazu werden in Phoenix internen Prozeduren benötigt, die den Ablauf einer PhoenixTransaktion steuern. Wenn der Beginn einer Transaktion mit dem Ausdruck "begin transaction" markiert wird, hat das den Aufruf der internen Phoenix-Prozedur "chimera_start_transaction" zur Folge. Diese Prozedur überprüft, ob eine nicht abgeschlossene Transaktion existiert. Ist das nicht der Fall wird eine neue PhoenixTransaktion durch den Phoenix-Befehl "start_transaction" gestartet. Danach kann mit der Abarbeitung einer Folge von Operationen begonnen werden, aus denen die Transaktion sich zusammensetzt. Existiert bereits eine offene Phoenix-Transaktion, so wird nichts unternommen, da eine neue Transaktion nicht innerhalb einer offenen Transaktion geöffnet werden kann und dies auch nicht erforderlich ist, da alle folgenden Operationen innerhalb der offenen Transaktion abgearbeitet werden können. Durch diese Operationen werden administrative Daten erzeugt, die für die Überprüfung von Integritätsbedingungen und zur Auslösung von Triggern erforderlich sind. Jede Operation wird als Ereignis registriert und zu diesem Zweck in die Phoenix-Relation "$chimera_event" eingetragen, die aus drei Attributen besteht. Das erste Attribut beinhaltet den Ereignisidentifikator (EID), durch den ein Ereignis innerhalb einer Transaktion eindeutig identifiziert wird. Das zweite Attribut spezifiziert die Operation, durch die das Ereignis ausgelöst worden ist. Das dritte Attribut beinhaltet die "oid", des betroffenen Tupels. Falls mehrere Tupel von einer Operation betroffen sind, 106 Inhaltsverzeichnis erfolgt pro Tupel ein Eintrag in die Phoenix-Relation "$chimera_event". Diese Einträge unterscheiden sich voneinander durch die "oid" des betroffenen Tupels. Der Abschluß einer Transaktion mit dem Befehl "commit" löst den Aufruf der internen Phoenix-Prozedur "chimera_commit" aus. Diese Prozedur überprüft zuerst, ob eine geöffnete Transaktion existiert, da nur in diesem Fall Modifikationen am Datenbestand noch nicht permanent durchgeführt worden sind. Existiert eine offene Phoenix-Transaktion, so wird das Ereignis "chimera_transaktion_end" explizit durch die Phoenix-Operation "raise" ausgelöst. Durch dieses Ereignis wird die Abarbeitung der Integritätsbedingungen und Trigger vom Typ "deferred" angestoßen. Nachdem alle Integritätsbedingungen und Trigger erfolgreich überprüft und ausgeführt worden sind, wird in der Phoenix-Prozedur "chimera_commit" dafür gesorgt, daß alle administrativen Daten, die zur Verwaltung von Ereignissen und der Ausführung und Überprüfung von Triggern und Integritätsbedingungen benötigt werden und die innerhalb der aktuellen Transaktion angefallen sind, explizit gelöscht werden. Anschließend wird die aktuelle Phoenix-Transaktion mit dem Phoenix-Befehl "commit" abgeschlossen und alle Modifikationen am Datenbestand permanent übernommen. Die explizite Verwendung des Ausdrucks "rollback" zur Markierung des Endes einer Transaktion löst im CPTPhx den Aufruf der Phoenix-Prozedur "chimera_rollback" aus. Diese Prozedur überprüft, ob eine offene Phoenix-Transaktion existiert. Nur wenn dies der Fall ist, wird durch den Phoenix-Befehl "rollback" die offen Phoenix-Transaktion zurücksetzt und auf diese Weise beendet. Da durch das Zurücksetzen einer Transaktion automatisch auch alle administrativen Daten gelöscht werden, die innerhalb der Transaktion angefallen sind, brauchen diese nicht wie bei einem "commit" explizit gelöscht zu werden. Die implizite Verwendung des Befehls "rollback" wird von Phoenix selbst gesteuert. Dieser Fall tritt ein, wenn eine Integritätsbedingung verletzt wird, und hat das Zurücksetzen der kompletten Transaktion zur Folge. Die Implementation von Chimera durch das CPTOracle muß das Chimera-Transaktionskonzept auf ähnliche Weise umsetzen. Um das Chimera-Transaktionskonzept zu realisieren, muß auch in einem Oracle-Datenbanksystem auf das Konzept der internen Prozeduren und Funktionen zurückgegriffen werden. Die Implementierung der internen Oracle-Prozedur (Oracle: stored procedure) "chimera_start_transaction" kann nicht überprüfen, ob eine offene Transaktion bereits existiert. Da aber der Beginn einer Oracle-Transaktion immer implizit vom Datenbankmanagementsystem markiert wird, sobald die erste Operation einer Transaktion an die Datenbank gerichtet wird, ist dies auch nicht erforderlich. Eine explizite Markierung des Beginns einer Oracle-Transaktion könnte durch die Verwendung des Ausdrucks "set transaction" umgesetzt werden. Da aber durch das DBMS bereits die implizite Markierung des Transaktionsanfangs vorgenommen wird, ist die explizite Markierung durch die Oracle-Prozedur "chimera_start_transaction" überflüssig. Die Implementation der Oracle-Prozedur "chimera_commit" muß den Oracle-Befehl "commit" aufrufen, um die Modifikationen, die innerhalb der Transaktion angefallen sind, permanent zur Verfügung gestellt werden und um die Transaktion zu beenden. Da das Triggerkonzept und Integritätsbedingungskonzept von Chimera im derzeitigen Stand der Implementierung noch nicht realisiert worden ist, kann an dieser Stelle nur gesagt werden, daß die organisatorischen Operationen zur Umsetzung dieser Konzepte vor dem Oracle107 Inhaltsverzeichnis Befehl "commit" müssen. in der Oracle-Prozedur "chimera_commit" aufgerufen werden Bei der Implementation der Oracle-Prozedur "chimera_rollback" tauchen keine Probleme im Zusammenhang mit Integritätsbedingungen und Triggern auf, da ein explizites Rollback die komplette Transaktion zurücksetzen muß und weder Integritätsbedingungen überprüft noch Trigger ausgelöst werden müssen. Um dies zu erreichen muß nur der OracleBefehl "rollback" aufgerufen werden. Ein Problem stellt die Behandlung eines impliziten Rollbacks dar. Ein implizites Rollback wird durch das DBMS von Oracle ausgelöst, sobald eine Transaktion gegen Integritätsbedingungen verstößt. Das Problem bei dem Transaktionskonzept von Oracle besteht darin, daß es sowohl ein globales als auch lokales implizites Rollback unterstützt. Ein globales, implizites Rollback wird immer am Ende einer Transaktion ausgelöst, wenn festgestellt wird, daß eine Integritätsbedingung vom Typ "deferred" durch eine Operation innerhalb der Transaktion verletzt worden ist. Es setzt die komplette Transaktion zurück, wie es auch laut Transaktionskonzept von Chimera sein soll. Ein lokales, implizites Rollback tritt direkt nach einer Operation auf, die eine Integritätsbedingung vom Typ "immediate" verletzt. Durch ein lokales Rollback wird nur die Operation zurückgesetzt, die auch die Verletzung der Integritätsbedingung verursacht hat. Es sind weder früher ausgeführte Operationen durch dieses lokale Rollback betroffen noch wird die Transaktion abgebrochen oder beendet. Diese Vorgehensweise entspricht nicht dem Transaktionskonzept von Chimera. Aus diesem Grund muß nach jeder Oracle-DMLOperation überprüft werden, ob ein lokales implizites Rollback stattgefunden hat. Diese Information kann über das Prolog-Prädikat "sql_lastmsg" zur Verfügung gestellt werden (siehe Kapitel 5). Im Falle eines lokalen, impliziten Rollbacks muß vom CPTOracle aus ein globales Rollback explizit angestoßen werden. Ein globales Rollback kann entweder durch den Aufruf der Oracle-Prozedur "chimera_rollback" durch das Prolog-Prädikat "sql_exec" oder aber durch das Prolog-Prädikat "sql_rollback" durchgeführt werden, die beide Bestandteil des Eclipse-Oracle-Interfaces sind. Um eine komplette Chimera-Transaktion übersetzen zu können, muß diese erst in Transaktionszeilen aufgeteilt werden. Eine Transaktion liegt sowohl im CPTPhx als auch im CPTOracle in Form einer Tokenliste vor. Diese Tokenliste wird in mehrere Tokenlisten aufgeteilt, wobei ein Semikolon innerhalb der Tokenliste bestimmt, an welcher Stelle die Liste geteilt werden soll. Auf diese Weise erhält man mehrere Tokenlisten, die jeweils eine Transaktionszeile beinhalten. Um nun eine Transaktionszeile zu übersetzen, muß sie in ihre einzelnen Operationen zerlegt und diese einzeln übersetzt werden. Die Aufteilung einer Transaktionszeile in ihre einzelnen Operationen übernimmt das Prolog-Prädikat "splitTransactionLine", welches die einzelnen Operationen extrahiert und in eine Liste von Operationen überführt. Im CPTOracle wird diese Liste von Operationen an das Prolog-Prädikat "translateDML" übergeben, durch welches die Übersetzung der einzelnen Operationen in SQL-Ausdrücke gesteuert wird. Anhand der Schlüsselwörter "add", "drop", "create", "modify", "delete", "select", "display", "generalize" und "specialize", mit denen eine Operation beginnen muß, wird festgestellt, um welchen Operationstyp es sich handelt, und der Aufruf des entsprechenden Prolog-Prädikats gesteuert, welches die eigentliche Übersetzung durchführt. Die Übersetzung der einzelnen Operationstypen wird in den Abschnitten 8.4 und 8.5 genauer erläutert. Vorher wird in Abschnitt 8.3 die Erzeugung und Verwaltung von Variablenbindungen erläutert, welche eine Voraussetzung zur Übersetzung von ChimeraOperationen ist. 108 Inhaltsverzeichnis 8.3 Erzeugung und Verwaltung von Variablenbindungen Ein Problem bei der Übersetzung von Chimera-Operationen in SQL-Operationen stellt die Erzeugung von Variablenbindungen und ihre Verwaltung dar. Da Phoenix ein auf Prolog basierendes DBMS ist, existiert dieses Problem dort nicht. Durch deklarative Ausdrücke werden in Phoenix Variablenbindungen erzeugt und durch das Prolog-System Eclipse verwaltet. Innerhalb einer SQL-DML-Operation können auch Variablenbindungen in Form einer Unteranfrage erzeugt werden. Diese gelten aber nur innerhalb dieser einen SQL-DML-Operation und können nicht in den folgenden Operationen weiter verwendet werden. Aus diesem Grund mußte eine Möglichkeit gefunden werden, durch SQL-DML-Operationen Variablenbindungen zu erzeugen und diese zu verwalten. Es existieren in Chimera die zwei folgenden DML-Operationen, die verwendet werden können, um Variablenbindungen zu erzeugen. Eine Anfrageoperation vom Typ "select" kann eine oder mehrere Instanzen einer Objektklasse an eine Variable binden. Eine DMLOperation vom Typ "create" bindet eine Variable an die in der "create"-Operation erzeugten Instanz. Die Instanz einer Chimera-Objektklasse wird im CPTPhx und im CPTOracle durch den Wert des Attributs "oid" repräsentiert. Jede Relation, die eine Objektklasse abbildet, besitzt dieses Attribut als Primärschlüssel. Ist nun eine Chimera-"select"Operation in eine SQL-"select"-Operation übersetzt worden, so wird sie mit Hilfe des Prolog-Prädikats "sql_query" aus dem Eclipse-Oracle-Interface an die Datenbank geschickt. Dieses Prädikat unifiziert eine Liste von Variablen mit den selektierten "oid"s (siehe Kapitel 5). In Kombination mit dem Prolog-Prädikat "findall" wird eine Liste aus den selektierten Tupeln erzeugt, die dann weiter verwendet wird, um die Daten abzuspeichern. Die Variablennamen in der Variablenliste ensprechen den Variablennamen aus der DML-Operation. Auf diese Weise werden die selektierten Werte der "oid"s den entsprechenden Variablen zugeordnet. Um nun eine Variable und ihre gebundenen "oid"s zu verwalten, wird eine Tabelle benötigt. Die Tabelle muß zwei Attribute besitzen. Das erste Attribut besitzt als Wert den Namen einer Variablen und wird deshalb mit dem Bezeichner "varname" versehen. Das zweite Attribut besitzt als Wert eine "oid", welche an die Variable gebunden worden ist. Der Bezeichner dieser Tabelle ist durch den Namen "chi_boundVar" festgelegt worden. VARNAME OID var_1 90 var_1 105 Die Tabelle "chi_boundVar" Diese Tabelle kann entweder als Prolog-Prädikat oder als Oracle-Tabelle realisiert werden. Der wesentliche Unterschied dieser beiden Ansätze liegt in der Formulierung der DMLOperationen, die auf gebundene Variablen zurückgreifen. Generell müssen die gebundenen Variablen im Bedingungsteil einer SQL-DML-Operation berücksichtigt werden. Dies erfolgt durch eine oder mehrere zusätzliche Bedingungen in der Bedingungsklausel. Wird nun die Tabelle durch ein Prolog-Prädikat realisiert, so müssen alle "oid"s der betroffenen 109 Inhaltsverzeichnis Variablen aus der Tabelle extrahiert und explizit in die Bedingungsklausel einer SQLOperation mit eingebaut werden. Das bedeutet auf das obige Beispiel bezogen, daß die Variablenbindungen der Variable "var_1" durch die beiden zusätzlichen Bedingungen "var_1.oid = 90 OR var_1.oid = 105" realisiert werden. Wird hingegen die Tabelle als Oracle-Tabelle realisiert, so brauchen die Werte der "oid"s nicht explizit in die Bedingungsklausel mit eingebunden zu werden, sondern sie werden implizit durch eine Unteranfrage aus der Tabelle "chi_boundVar" eingebunden. Die entsprechende Bedingung sieht auf das obige Beispiel bezogen wie folgt aus: var_1.oid = ( SELECT oid FROM chi_boundVar WHERE varname = 'var_1' ) Wir haben uns für die Lösung des Problems durch eine Oracle-Tabelle entschieden, da dies die Formulierung der zusätzlichen Bedingungen in der SQL-Operation vereinfacht. Es braucht dadurch nur noch eine Bedingung formuliert zu werden, die den explizit formulierten Bedingungen in ihrer Bedeutung entspricht. Auf diese Weise wird die Generierung der erforderlichen Bedingungen aus dem Prolog-Programm herausgenommen und durch das DBMS von Oracle durchgeführt. 8.4 Übersetzung von Anfragen In Chimera existieren die zwei Anfragetypen "select" und "display", die unterschiedliche Aufgabenbereiche abdecken. In Oracle existiert hingegen nur die Anfrageoperation "select", die zur Umsetzung beider Chimera-Anfragetypen verwendet wird. Der ChimeraAnfragetyp "select" wird ausschließlich benutzt, um Variablenbindungen zu erzeugen, die in anderen Operationen weiter verwendet werden können. Durch diese Eigenschaft ist der Chimera-"select"-Operation vergleichbar mit dem Konzept der Unteranfrage in einer SQL-DML-Operation. Der Operationstyp "select" wird im CPTOracle durch das PrologPrädikat "translateSelect" analysiert. Es liefert die Parameter, die von dem PrologPrädikat "sql_query" benötigt werden, um die entsprechende SQL-Operation aufzubauen und an die Datenbank zu schicken. Der erste Parameter des Prädikats "sql_query" besteht aus der Liste von Attributen, die selektiert werden sollen. Da Variablenbindungen erzeugt werden, muß immer nur die "oid" eines Tupels aus einer Tabelle selektiert werden. Deshalb wird für jede Variable vor dem Bedingungsteil einer "select"-Operation in ChimeraSyntax, eine "oid" aus einer Tabelle selektiert, die eine Objektklasse des ChimeraDatenbankschemas repräsentiert. Die Variablennamen einer Chimera-"select"-Operation werden in der "from"-Klausel einer SQL-Operation als Tupelvariable für die Tabellen verwendet, aus denen die "oid"s selektiert werden. Durch diese Vorgehensweise kann das Attribut "oid" durch den Ausdruck "variablen_name.oid" angesprochen werden. Die Verbindung zwischen Tupelvariable und Tabelle wird im Bedingungsteil der "select"Operation in Chimera-Syntax festgelegt, der durch das Prolog-Prädikat "translateDecExp" in eine SQL-"from"- und einer SQL-"where"-Klausel übersetzt wird. Die "from"-Klausel wird aus den Klassenformeln im Bedingungsteil der Chimera"select"-Operation zusammengesetzt. Dabei wird der Klassenname in die SQL-"from"Klausel übernommen und der Variablenname der Klassenformel als Tupelvariable vereinbart. 110 Inhaltsverzeichnis Die "from"-Klausel entspricht dem zweiten Parameter des Prolog-Prädikats "sql_query". Die "where"-Klausel, die dem dritten Parameter des verwendeten PrologPrädikats entspricht, wird aus den Bedingungen zusammengesetzt, die keine Klassenformeln sind. Die Übersetzung dieser deklarativen Ausdrücke ist im Kapitel 7 bereits beschrieben worden. Das folgende Beispiel verdeutlicht noch einmal die Vorgehensweise bei der Übersetzung einer "select"-Operation. Chimera-DML select( X,Y where person(X), person(Y), X.name = Y.name, X.name = 'Scheuber') Oracle-DML SELECT FROM WHERE AND X.oid, person X.name X.name Y.oid X, person Y = Y.name = 'Scheuber'; sql_query( ['X.oid', 'Y.oid'],"person X, person Y", "X.name = Y.name AND X.name = 'Scheuber'", "",[X,Y] ) Beispiel 8.4.1 Übersetzung des Anfragetyps "select" In dem Beispiel 8.4.1 werden die Variablen "X" und "Y" der Klassenformeln "person(X)" und "person(Y)" als Tupelvariablen in der SQL-"from"-Klausel verwendet. Der deklarative Ausdruck "person(X)" entspricht in seiner Bedeutung dem Ausdruck "person X". Dadurch ist es möglich die Attribute in den beiden Operationen durch den identischen Ausdruck anzusprechen. Die selektierten "oid"s werden durch das PrologPrädikat "sql_query" mit den Variablen der Liste " [X,Y]" unifiziert. Die Variablennamen und die dazugehörigen Werte werden durch SQL-"insert"-Operationen in die Oracle-Tabelle "chi_boundVar" übertragen, wodurch Variablenbindungen erzeugt werden, die in anderen Operationen weiter verwendet werden können. Pro selektierten Tupel wird eine "insert"-Operation erzeugt. Der Operationstyp "display" wird im CPTOracle durch das Prolog-Prädikat "translateDisplay" analysiert, um die benötigten Parameter für das Prolog-Prädikat "sql_querydistinct" zu konstruieren. Dieses Prädikat wird verwendet, da in Chimera durch die "display"-Operation keine Duplikate angezeigt werden. Der Anfragetyp "display" wird ausschließlich dazu verwendet, Daten aus der Datenbank zu extrahieren und auszugeben. Es existieren zwei unterschiedliche Möglichkeiten eine "display"Operation zu formulieren. Entweder wird in einer "display"-Operation auf bereits erzeugte Variablenbindungen zurückgegriffen oder aber es muß ein Bedingungsteil innerhalb der "display"-Operation formuliert werden. Allerdings ist es zur Zeit nicht möglich, beide Alternativen innerhalb einer "display"-Operation zu kombinieren, da dieser Fall bisher nicht in der Implementation berücksichtigt worden ist. Um nun eine "display"-Operation in eine SQL-Operation zu übersetzen, wird als erstes die Liste von Attributen benötigt, die angezeigt werden sollen. Diese werden durch das Prolog-Prädikat "getSelAttributes" aus der Tokenliste extrahiert, welche die Chimera-"display"-Operation enthält. Da wieder 111 Inhaltsverzeichnis die verwendeten Variablennamen als Tupelvariable für die Tabellen in der entsprechenden SQL-Operation eingesetzt werden, ist es möglich, die Attributnamen eins zu eins zu übernehmen. Wird nun ein Bedingungsteil in einer "display"-Operation formuliert, so wird er genauso übersetzt, wie schon bei den Chimera-"select"-Operationen beschrieben. Chimera-DML display( X.name, where person(X), X.name = 'Horn' ) sql_querydistinct( Oracle-DML SELECT FROM WHERE X.name, X.vorname person X X.name = 'Horn'; ['X.name','X.vorname'], "person X", " X.name = 'Horn'", "", [Name,Vorname]) Beispiel 8.4.2 Übersetzung einer "display"-Operation mit Bedingungen Existiert nun innerhalb der "display"-Operation kein Bedingungsteil, so wird über die verwendeten Variablennamen im Pfadausdruck der Attribute, die "from"- und "where"Klausel der SQL-Operation aufgebaut. Die dazu benötigten Variablenbindungen werden über das Prolog-Prädikat "varInfo" und die Oracle-Tabelle "chi_boundVar" zur Verfügung gestellt. Das Prolog-Prädikat "varInfo" liefert zu einem Variablennamen den Namen der Objekttklasse, an dessen Instanzen die Variable gebunden ist. Durch diese Informationen kann die "from"-Klausel der SQL-"select"-Operation aufgebaut werden, indem für jede Variable der zugehörige Objektklassenname selektiert wird. Die Variable wird wieder als Tupelvariable für die entsprechende Sicht verwendet. Die "where"-Klausel wird dadurch aufgebaut, daß für jede in der "display"-Operation verwendete Variable eine Bedingung formuliert wird. Diese Bedingung stellt die Verbindung zwischen der Variable und den gebundenen "oid"s her. Chimera-DML select( X where person(X), X.name = 'Horn' ), display(X.name, X.vorname). Oracle-DML SELECT X.name,X.vorname FROM person X WHERE X.oid = ( SELECT X.oid FROM chi_boundVar WHERE varname = X ); sql_query( ['X.name','X.vorname'], "person X", "X.oid = ( SELECT X.oid FROM chi_boundVar WHERE varname = X )", "", [X,Y] ) Beispiel 8.4.3: Übersetzung einer "display"-Operation ohne Bedingungen 112 Inhaltsverzeichnis In dem Beispiel 8.4.3 werden die Werte der selektierten Attribute "name" und "vorname" durch das Prolog-Prädikat "sql_querydistinct" mit den Variablen der Liste "[Name,Vorname]" unifiziert. Durch die Verwendung des Prolog-Prädikats "findall" werden alle Tupel in Form einer Liste zurückgegeben. Danach erfolgt pro selektierten Tupel die Ausgabe der Variablennamen und ihrer dazugehörigen Werte. 8.5 Übersetzung von DML-Operationen Zu den DML-Operationen gehören in der Sprachspezifikation von Chimera die Operationstypen "create", "delete" und "modify". Diese werden verwendet, um Instanzen von Objektklassen zu generieren, zu löschen oder zu modifizieren. Die weiteren DMLOperationstypen "add" und "drop" dienen dazu, Werteklassen mit den erforderlichen Daten zu füllen. Im folgenden wird die Vorgehensweise zur Übersetzung dieser DMLOperationen beschrieben. Der Operationstyp "add" wird im CPTOracle durch das Prolog-Prädikat "translateAdd" analysiert, um eine SQL-"insert"-Operation zu konstruieren. Diese "insert"-Operation legt eine neue Instanz in der Tabelle an, welche die Werteklasse repräsentiert. Bei der Formulierung der Operation muß darauf geachtet werden, daß jede Tabelle, die eine Werteklasse repräsentiert, zusätzlich zu ihren in Chimera definierten Attributen, ein weiteres Attribut besitzt. Dieses Attribut, welches unter dem Namen "vid" angelegt wird, ist der Primärschlüssel der Tabelle. Durch ihn wird ein Tupel in der Tabelle eindeutig identifiziert. Um einen eindeutigen Wert für dieses Attribut generieren zu können, wird das OracleKonzept der "sequence" verwendet. Eine "sequence" ist eine Pseudospalte (siehe Kapitel 4), deren Wertebereich durch den Datentyp "number" festgelegt ist. Durch die Funktion "nextval" wird der Wert einer "sequence" sukzessiv um einen festgelegten Wert erhöht. Dadurch ist garantiert, daß immer ein eindeutiger Wert für das Attribut "vid" innerhalb des Datenbankschemas zur Verfügung steht. Die "sequence" für "vid"s wird wie folgt definiert: CREATE SEQUENCE chi_vid_seq; Da kein spezieller Wert definiert worden ist, um den die "sequence" bei Aufruf der Funktion "nextval" erhöht werden soll, wird sie standartmäßig durch die Addition des Wertes 1 inkrementiert. Ein fester Wert zur Addition kann durch die Klausel "increment by" spezifiziert werden. Die komplette SQL-Operation wird durch das Prolog-Prädikat "sql_exec" und nicht durch "sql_insert" an die Datenbank geschickt, da bei "sql_insert" eine Liste von Attributnamen als Parameter benötigt wird. Da die gesamte Definition einer Werteklasse analysiert werden muß, um festzustellen, wieviele Attribute sie besitzt und wie deren Bezeichner lauten, wird die komplette SQL-Operation in Form einer Zeichenkette an das Prolog-Prädikat "sql_exec" übergeben. Dies hat den Vorteil, daß keine Attributnamen in der Operation spezifiziert werden müssen, da die "insert"-Operation allen Attributen der Tabelle einen Wert zuweist. Die Zuordnung zwischen Werten und Attributen erfolgt in Abhängigkeit der Reihenfolge der übergebenen Werte und der Reihenfolge, in der die Attribute der Tabelle definiert worden sind. Das erste Attribut einer Tabelle, die eine Werteklasse ab113 Inhaltsverzeichnis bildet, ist immer die "vid". Danach werden die eigentlichen Attribute definiert, welche die Werteklasse beinhaltet. Diese Attribute werden in der gleichen Reihenfolge angelegt, wie sie auch in der Chimera-Werteklasse spezifiziert worden sind. Aus diesem Grund ist auch die Reihenfolge der Werte aus der "add"-Operation einfach auf die Reihenfolge der Werte in der "insert"-Operation übertragbar. Chimera-DML add( vc_abteilung, ['EDV','Schmitz'] ) Oracle-DML INSERT INTO vc_abteilung VALUES( chi_vid_seq.nextval, 'EDV','Schmitz'); sql_exec( "INSERT INTO vc_abteilung VALUES( chi_vid_seq.nextval, 'EDV', 'Schmitz' )", Fehlercode, Fehlermeldung, _ ) Beispiel 8.5.1: Übersetzung einer Chimera-"add"-Operation Im Beispiel 8.5.1 wird in die Tabelle "vc_abteilung", die im Kapitel 6 als Beispiel zur Übersetzung einer Werteklasse eingeführt worden ist, ein neuer Datensatz eingefügt. Die Werte, die den Attributen der Tabelle zugewiesen werden, setzen sich aus einer eindeutigen "vid", und den Werten "EDV" und "Schmitz" zusammen. Der Wert der "vid" wird durch den Ausdruck "chi_vid_seq.nextval" generiert, wobei "chi_vid_seq" der Name der benutzten Sequenz und "nextval" die Funktion ist, die auf sie angewendet wird. Die beiden anderen Werte werden aus der Liste des zweiten Parameters der "add"-Operation extrahiert und als Werte für die Attribute "bereich" und "leiter" verwendet. Der Operationstyp "drop" wird im CPTOracle durch das Prolog-Prädikat "translateDrop" analysiert, um die erforderlichen Parameter für das Prädikat "sql_delete" zu konstruieren, durch welches die entsprechende SQL-"delete"Operation erzeugt wird. Als erster Schritt müssen die Attributnamen der Werteklasse aus dem CDD extrahiert werden, da sie zur Umsetzung der "drop"-Operation explizit in der Bedingungsklausel der SQL-Operation benötigt werden. Da Informationen über die Attribute einer Werteklasse nicht getrennt im CDD verwaltet werden, muß ihre komplette Definition analysiert werden, um herauszufinden, ob der Wertetyp nur ein einziges Attribut besitzt oder aber sich aus mehreren Attributen in Form eines benutzerdefinierten Datentyps zusammensetzt. Besitzt die Chimera-Werteklasse nur ein Attribut, so wird dieses Attribut in der entsprechenden Oracle-Tabelle standardmäßig mit dem Namen der Werteklasse bezeichnet, da kein expliziter Name in der Chimera-Werteklasse für ein einzelnes Attribut vorgesehen ist. 114 Inhaltsverzeichnis Chimera-DML drop( vc_abteilung, ['EDV','Schmitz'] ) Oracle-DML DELETE FROM vc_abteilung WHERE bereich = 'EDV' AND leiter = 'Schmitz'; sql_delete( "vc_abteilung", "", ['bereich','leiter'], ['EDV','Schmitz'], _ ) Beispiel 8.5.2: Übersetzung einer Chimera-"drop"-Operation Um die "drop"-Operation aus dem Beispiel 8.5.2 umsetzen zu können, müssen zuerst die Attributnamen "bereich" und "leiter" aus der Definition der Werteklasse "vc_abteilung", die im CDD gespeichert vorliegt, extrahiert werden. Die beiden Attributnamen werden in Form einer Liste als dritter Parameter in dem Prolog-Prädikat "sql_delete" verwendet. Die Liste aus der "drop"-Operation, welche die beiden Werte enthält, durch die eine Instanz der Tabelle "vc_abteilung" eindeutig identifiziert werden kann, wird eins zu eins als vierter Parameter des Prolog-Prädikats "sql_delete" verwendet. Aus diesen beiden Listen, die als Parameter verwendet werden, wird durch "sql_delete" die Bedingungsklausel für die SQL-"delete"-Operation zusammengesetzt (siehe Kapitel 5) und die komplette Operation an die Oracle-Datenbank geschickt. Der Operationstyp "create" wird im CPTOracle durch das Prolog-Prädikat "translateCreate" analysiert, um die erforderlichen Parameter für das Prädikat "sql_insert" zur Verfügung zu stellen. Aus diesem Grund werden mit Hilfe des PrologPrädikats "getAttributeValue" zwei Listen aus der Tokenliste der "create"Operation generiert. In der ersten Liste sind alle Attributnamen und in der zweiten Liste die dazugehörigen Attributwerte enthalten. Zusätzlich zu den Attributnamen aus der "create"-Operation wird noch die "oid" an erster Stelle der Liste mit aufgenommen. Der Wert des Attributs "oid" wird durch die Verwendung der folgenden Oracle"sequence" erzeugt, um einen eindeutigen Wert zu garantieren: CREATE SEQUENZ chi_oid_seq; Der Ausdruck "chi_oid_seq.nextval" wird als erster Wert in der Werteliste verwendet und erzeugt die eindeutige "oid" für den neu angelegten Datensatz. Diese beiden Listen werden zusammen mit dem Namen der betroffenen Objektklasse an das Prolog-Prädikat "sql_insert" (siehe Kapitel 5) übergeben, welches aus diesen drei Parametern die SQL"insert"-Operation aufbaut und ihn an die entsprechende Sicht in der Oracle-Datenbank schickt. Durch die Instead-of-Trigger der Sicht, werden die Daten aus der "insert"Operation an die entsprechenden Basistabellen der Sicht verteilt. Ein weiteres Problem bei der Übersetzung einer Chimera-"create"-Operation besteht in der Generierung der erforderlichen Variablenbindung. Eine Chimera-"create"-Operation 115 Inhaltsverzeichnis bindet die in ihr verwendete Variable an die von ihr neu erzeugte Instanz einer Objektklasse. Um eine äquivalente Variablenbindung im CPTOracle zu erzeugen, wird zusätzlich zu der übersetzten "create"-Operation eine weitere SQL-"insert"-Operation an die Tabelle "chi_boundVar" gerichtet. Diese Operation fügt einen zweistelligen Tupel ein, dessen Werte sich aus dem Variablennamen aus der "create"-Operation und der "oid" der neu erzeugten Instanz zusammensetzen. Auf die "oid" der neu erzeugten Instanz kann ganz einfach zugegriffen werden, da sie dem aktuellen Wert der Sequenz "chi_oid_seq" entspricht. Auf diesen Wert kann man mit Hilfe der Funktion "currval" zugreifen. Chimera-DML Oracle-DML create( person, INSERT INTO person ( name: 'Scheuber', ( oid, name, vorname ) vorname: 'Andrea' VALUES( chi_oid_seq.nextval, ), X ); 'Scheuber', 'Andrea' ); INSERT INTO chi_boundVar ( varname, oid ) VALUES ('X',chi_oid_seq.nextval); sql_insert("person",['oid','name','vorname'], [chi_oid_seq.nextval,'Scheuber','Andrea']) sql_insert("chi_boundVar",['varname','oid'], ['X',chi_oid_seq.nextval] ) Beispiel 8.5.3: Übersetzung einer Chimera-"create"-Operation Im Beispiel 8.5.3 wird in der Objektklasse "person" durch eine "create"-Operation eine neue Instanz angelegt. Um nun eine äquivalente "insert"-Operation zu generieren wird das Prolog-Prädikat "sql_insert" verwendet, welches drei Parameter dazu benötigt. Diese Parameter erhält man durch die Analyse der Tokenliste, welche die "create"Operation enthält. Der erste Parameter besteht aus dem Namen der Objektklasse "person". Der zweite Parameter beinhaltet eine Liste der Attribute, welche zu der Objektklasse gehören. An erster Stelle dieser Liste, wird zusätzlich das Attribut "oid" eingefügt, da jede OracleSicht, die eine Objektklasse repräsentiert zusätzlich das Attribut "oid" als Objektidentifikator besitzt. Auf diese Weise ergibt sich die Attributliste "['name','vorname']" der als zweiter Parameter des Prädikats "sql_insert" verwendet wird. Der dritte Parameter beinhaltet die Liste der entsprechenden Attributwerte. An erster Stelle dieser Liste wird der Wert der neuen "oid" durch die Funktion "chi_oid_seq.nextval" beschrieben. Daraus ergibt sich die Liste "[chi_oid_seq.nextval,'Scheuber','Andrea']". Aus diesen drei Parametern wird die erste "insert"-Operation konstruiert und an die entsprechende Sicht in der Oracle-Datenbank geschickt. Diese insert-Operation löst den 116 Inhaltsverzeichnis Instead-of-Insert-Trigger der Sicht "person" aus, der dafür zuständig ist, die neue Instanz an die entsprechende Basistabelle weiterzuleiten. Die Werteliste der zweiten "insert"Operation setzt sich aus dem Namen der Variablen "X" und der Funktion "chi_oid_seq.nextval" zusammen. Durch diese "insert"-Operation wird die Variablenbindung für die Variable "X" erzeugt. Der Operationstyp "delete" wird im CPTOracle durch das Prolog-Prädikat "translateDelete" in den SQL-Operationstyp "delete" überführt. Um eine Chimera"delete"-Operation korrekt formulieren zu können, muß an die Variable, die in der "delete"-Operation benutzt wird, durch vorher durchgeführte Anfragen vom Operationstyp "select" Instanzen der Objektklasse gebunden werden. Diese gebundenen Variablen werden in der Oracle-Tabelle "chi_boundVar" gespeichert und eine Unteranfrage in die SQL-Operation integriert. Der Name, der betroffenen Objektklasse und der Bedingungsteil, der SQL-"delete"-Operation werden an das Prädikat "sql_delete" des EclipseOracle-Interfaces übergeben, durch das die SQL-Operation generiert und an die entsprechende Sicht in der Datenbank geschickt wird. Chimera-DML select( X where person(X), X.name = 'Scheuber'), delete( person, X ); Oracle-DML DELETE WHERE ( SELECT FROM WHERE FROM person oid = oid chi_boundVar varname = X ); sql_delete("person", "oid=(SELECT oid FROM chi_boundVar WHERE varname=X", [],[], RowsDeleted ) Beispiel 8.5.4: Übersetzung einer Chimera-"delete"-Operation Dadurch, daß nur die gebundenen Variablen aus der Tabelle "chi_boundVar" ausschlaggebend dafür sind, welche Instanzen durch eine "delete"-Operation gelöscht werden, ist es nur erforderlich den Bedingungsteil der SQL-Operation so zu spezifizieren, daß alle Datensätze aus der Sicht "person", deren "oid" in der Tabelle "chi_boundVar" an die Variable "X" gebunden ist, gelöscht werden. Diese "delete"-Operation löst den Instead-ofDelete-Trigger der Sicht "person" aus, durch welchen alle betroffenen Instanzen in der Basistabelle "oc_person" gelöscht werden. Der Operationstyp "modify" wird im CPTOracle durch das Prolog-Prädikat "translateModify" in den SQL-Operationstyp "update" überführt. Auch bei diesem Ausdruck wird eine vorher gebundene Variable benötigt, durch die der Bedingungsteil der "update"-Operation aufgebaut wird, wie schon bei der Übersetzung der Chimera"delete"-Operation beschrieben. Da kein Prolog-Prädikat im Eclipse-Oracle-Interface existiert, welches speziell für "update"-Operationen konzipiert worden ist, muß auf das all117 Inhaltsverzeichnis gemeinere Prädikat "sql_exec" zurück gegriffen werden. Durch dieses Prädikat können beliebige SQL-Operationen an die Datenbank geschickt werden, die mit dem Oracle-Befehl "execute" ausgeführt werden. Chimera-DML modify( person.name, X, 'Horn'); Oracle-DML UPDATE SET WHERE person name = 'Horn' oid = ( SELECT oid FROM chi_boundVar WHERE varname = X); sql_exec( "UPDATE person SET name = 'Horn' WHERE oid = ( SELECT oid FROM chi_boundVar WHERE varname = X)", Fehlercode, Fehlermeldung, ZeilenAnzahl ) Beispiel 8.5.5: Übersetzung einer Chimera-"modify"-Operation Im Beispiel 8.5.5 wird gezeigt, wie eine Chimera-"modify"-Operation in eine SQL"update"-Operation überführt wird. Aus der Tokenliste der Chimera-"modify"-Operation wird der Objektklassenname "person", der Attributname "name", der neue Attributwert 'Horn' und der Variablenname "X", an den Instanzen der Objektklasse gebunden sein müssen extrahiert. Mit Hilfe dieser Daten läßt sich die SQL-"update"-Operation wie folgt formulieren. Der Name der Chimera-Objektklasse "person" entspricht dem Namen der Oracle-Sicht "person", welche die Objektklasse repräsentiert. Das Attribut "name" der Sicht wird mit dem neuen Attributwert gleichgesetzt. Dies gilt für alle Instanzen der Sicht "person", deren "oid" durch einen Tupel in der Tabelle "chi_boundVar" an die Variable "X" gebunden ist. Diese "update"-Operation auf der Sicht "person" löst den zur Sicht dazugehörigen Instead-of-Update-Trigger aus, der dafür sorgt, daß die Modifikation an dem Attribut "name" in die Basistabelle "oc_person" übertragen wird. 118 Inhaltsverzeichnis Andrea Scheuber und Michael Horn 9 Zusammenfassung und Ausblick Die bisherige Implementierung des CPTPhx basiert auf dem in ECLiPSe-Prolog realisierten Datenbankmanagementsystem Phoenix. Phoenix ist eine universitäre Implementierung des relationalen Datenmodells mit einer Erweiterung für aktive und deduktive Regeln. Das CPTPhx übernimmt hierbei die Aufgabe, die Konzepte eines Chimera-Schemas, der aktiven und deduktiven Regeln sowie der Datenmanipulationssprache von Chimera auf das relationale System Phoenix abzubilden. Im Umfeld des CPTPhx wurde durch mehrerer Forschungs- und Diplomarbeiten eine Umgebung für den Entwurf und die Analyse von objektorientierten Chimera-Schemata geschaffen. Im Rahmen dieser Ausarbeitung wurde die Basis für eine neue, zweite Implementierung gelegt, dem CPTOracle. Das experimentelle Datenbankmanagementsystem Phoenix sollte durch das kommerzielle objekt-relationale DBMS Oracle8 ersetzt werden. Die Übersetzung des objektorientierten Datenmodells von Chimera auf das objekt-relationale Datenmodell von Oracle8 stand hierbei im Vordergrund. Basierend auf den unterschiedlichen Fähigkeiten von Oracle8 und Phoenix wurde ein anderer Weg für die Übersetzung eines Chimera-Schemas gewählt. Das in Oracle8 neu eingeführte Konzept der "instead-of"-Trigger ermöglichte dieses unterschiedliche Vorgehen. Der zweite Aspekt dieser Diplomarbeit lag in der Übersetzung der imperativen Ausdrücke der in Chimera definierten Datenmanipulationssprache und die Übertragung des Transaktionsmodells von Chimera nach Oracle8. Das Transaktionskonzept von Chimera wurde mit Hilfe interner Prolog-Prädikate und Oracle8-Tabellen auf das Transaktionskonzept von Oracle8 übertragen. Der dritte Aspekt dieser Arbeit liegt in der Übersetzung deklarativer Ausdrücke von Chimera nach Oracle8-SQL. Deklarative Ausdrücke werden zur Formulierung von Anfragen und zur Definition von Klassenpopulations- und Attributdefinitionsregeln, von Integritätsbedingungen, Triggern und Operationen verwendet. 119 Inhaltsverzeichnis Obige Aspekte der Übersetzung wurden in ECLiPSe-Prolog implementiert. Die Verbindung zwischen dem Prolog-System und dem DBMS Oracle8 wurde durch die bereits existierende Schnittstelle zwischen ECLiPSe und Oracle8 von Thomas Kolbe ([Kol95]) realisiert. Zusätzlich zu den übersetzten Aspekten existieren noch Konzepte, die im Rahmen dieser Diplomarbeit nicht mehr vollständig behandelt werden konnten. Die restlichen Abschnitte dieses Kapitels erläutern Ideen zur Umsetzung von listen- und mengenwertigen Attributen und Wertetypen, der Integritätsbedingungen und Trigger von Chimera. Bisher können Listen und Mengen nicht von der Implementation des CPTOracle verarbeitet werden. Folgender Abschnitt wird einen Lösungsansatz vorstellen, der dieses Manko entfernen könnte. Listen sind Ansammlungen von Elementen, die jeweils eindeutig sein müssen und in einer festen Reihenfolge eingegeben wurden. Diese Bedingungen können durch die Realisierung einer Liste durch eine Oracle8-Tabelle realisiert werden. Die Tabelle müßte folgende Spalten besitzen: • Spalte für den Objektidentifikator • Spalte für eine eindeutigen Reihenfolgenindikator • Spalte für den Wert des Listenelements Durch obige Darstellung könnten die Listeneinträge eines Attributes abgespeichert werden. Die Eindeutigkeit der Einträge kann durch eine Schlüsselbedingung für die beiden Spalten des Objektidentifikatoren und des eigentlichen Wertes sichergestellt werden. Zwischen der Objektklasse und der Listen-Tabelle besteht eine 1:n Verbindung. Dies bedeutet, daß ein Objekt mehrere Listeneinträge in der Tabelle abspeichern darf. Mengen unterscheiden sich nur durch die nicht vorhandene Reihenfolge innerhalb der Werte und durch die nicht geforderte Eindeutigkeit der einzelnen Werte. Menge könnten daher auf die gleiche Art und Weise implementiert werden, wie für Listen empfohlen. Die Tabelle, die eine Menge repräsentiert kommt allerdings mit nur zwei Spalte aus: • Spalte für den Objektidentifikator • Spalte für den Wert des Listenelements Die Spalte zur Speicherung der Reihenfolge wird in den ungeordneten Mengen nicht mehr benötigt. Die Ideen zur Übersetzung von Listen und Mengen haben allerdings folgende Auswirkungen auf die in dieser Diplomarbeit beschriebene Implementierung: • Anfragen an eine Chimera-Objektklasse mit einem listen- oder mengenwertigen Attribut müssen die Liste bzw. die Menge verarbeiten können. Die Oracle8-Sichten, die eine Chimera-Objektklasse repräsentieren, sind nicht in der Lage, mit dieser Art von Attributen umzugehen. Das Datenmodell von Oracle8 unterstützt keine komplexen Attributdefinitionen, die eine Liste oder Menge repräsentieren. 120 Inhaltsverzeichnis • Die Übersetzung der Datenmanipulationsbefehle von Chimera müssen ebenfalls an diese Darstellung von Listen und Mengen angepaßt werden. • Es muß eine Funktionalität entwickelt werden, die es ermöglicht, eine neues Element in die Mitte einer Liste einzufügen. Diese Operation muß den Reihenfolgenindikator der in der Liste folgenden Elemente verändern. Das obig beschriebene Vorgehen kann ebenfalls bei der Übersetzung listen- und mengenwertige Wertetypen angewendet werden. Durch die Realisierung der Listen- und Mengenstruktur in Form einer Tabelle können Integritätsbedingungen einmal, zentral definiert werden. Die Implementierung des CPTOracle kann bis jetzt noch keine Integritätsbedingungen von Chimera nach Oracle übersetzen. Auch wenn es auf den ersten Blick so aussieht, als ob Integritätsbedingungen in Chimera und Oracle doch sehr ähnlich wären, so sieht das bei genauerer Betrachtung doch ganz anders aus: Das Konzept der Integritätsbedingungen ChimeraModells (siehe Kapitel 2) ist sehr viel mächtiger als das Konzept der built-inIntegritätsbedingungen des Oracle8-Datenmodells (siehe Kapitel 4). Ziel einer Übersetzung von Chimera-Integritätsbedingungen nach Oracle8 muß es also sein, die Einschränkungen auf Seiten von Oracle8 so weit wie möglich aufzuheben. Trotz der markanten Unterschiede, existiert dennoch eine kleine Schnittmenge von Klassen von Integritätsbedingungen, die beide Modelle unterstützen: • "notnull"-Bedingungen für ein Attribut • Primär- und Sekundärschlüssel für eine Tabelle Diese beiden Klassen können demnach auf das jeweilige Äquivalent übertragen werden. Bei den komplexeren, selbstdefinierten Integritätsbedingungen sieht es dagegen vollkommen anders aus: Chimera-Integritätsbedingungen können im Rumpf der Bedingung durch beliebige deklarative Ausdrücke formuliert werden. Der Umfang der "check"-Bedingungen von Oracle8 entspricht nicht einmal annähernd dem der deklarativen Ausdrücke von Chimera. Innerhalb einer "check"-Integritätsbedingung dürfen keine Anfragen auf den Datenbestand erfolgen. Des weiteren ist es nicht möglich, die Zugehörigkeit eines Wertes zu einer Menge zu fordern, wenn diese Menge sich während der Laufzeit der Datenbank verändern kann. Die Lösung für obige Probleme könnte die Übersetzung von Chimera-Integritätsbedingungen in Oracle8-Trigger sein. Dieser Ansatz der Problemlösung hätte noch einen zusätzlichen Vorteil: Das Oracle8-Datenmodell erlaubt keine Definition von Integritätsbedingungen für Sichten. Bei der Übersetzung eines Chimera-Schemas in ein Oracle8-SQL-Schema werden Sichten allerdings zur Darstellung von Objektklassen verwendet (vergleiche Kapitel 6). Das Aufspalten der Definition einer Chimera-Integritätsbedingung auf die verschiedenen Oracle8Tabellen ist allerdings nicht möglich. Die bisherige Implementierung des CPTOracle unterstützt noch keinerlei Schemaevolution. Daher können Integritätsbedingungen nur zu Beginn der Schemadefinition definiert werden. Eine Integritätsverletzung kann also nur durch eine Datenmanipulation geschehen, wenn man einmal davon ausgeht, daß alle bisher eingefügten und veränderten Daten einen konsistenten Datenbankzustand definieren. Alle DML-Operationen von Chimera werden auf der Seite von Oracle durch "instead-of"-Trigger realisiert. Innerhalb dieser Trigger kann daher die 121 Inhaltsverzeichnis komplette Überprüfung aller Integritätsbedingungen einer Chimera-Objektklasse realisiert werden. Es bietet sich an, eine komplexe Integritätsbedingung von Chimera in eine Oracle8Datenbankfunktion ("stored function") zu übersetzen. Oracle8-Datenbankfunktionen werden mit Hilfe der Oracle-Programmiersprache PL/SQL formuliert. PL/SQL ist eine Erweiterung von SQL um Kontrollstrukturen u.ä. Jede Integritätsbedingung eines ChimeraSchemas könnte in eine Funktion übersetzt werden. Die Funktion würde von den jeweiligen "instead-of"-Triggern einer übersetzten Objektklasse aufgerufen werden. Verletzungen einer Integritätsbedingung müssen zentral für eine Chimera-Datenbank auf einem Oracle8-Server verwaltet werden. Dieses Vorgehen ist nötig, da z.B. Trigger auf Integritätsverletzungen automatisch reagieren können. Die Implementierung des CPTPhx hat das Problem durch eine extensionale Relation gelöst, in der alle Verletzungen einer Integritätsbedingung protokolliert werden. Dieses Vorgehen läßt sich ohne Probleme für das CPTOracle übernehmen. Die entsprechende Oracle8-Tabelle sollte mindestens folgende Informationen einer Integritätsverletzung speichern: • Namen der Objektklasse • Namen der verletzten Integritätsbedingung • Identifikator des inkonsistenten Objektes (OID) • Operation, bei der die Verletzung auftrat Obige Liste erhebt keinen Anspruch auf Vollständigkeit, da eine Implementierung obiger Ideen eventuell noch weitere Informationen benötigt. Es könnte z.B. möglich sein, daß die Werte der Datenmanipulation zusätzlich interessant sind. Das bisher vorgestellte Verfahren bezieht sich auf Integritätsbedingungen, die sofort nach einer Datenmanipulation überprüft werden müssen ("immediate constraints"). Die Integritätsbedingungen, die an Ende einer Transaktion überprüft werden sollen, können allerdings durch ein ähnliches Verfahren übersetzt werden. Der einzige Unterschied stellt der Aufruf der Integritätsüberprüfung da. Der DML-Befehl "commit" muß durch eine entsprechende Funktion oder Prozedur eingeschlossen werden. Die Funktion oder Prozedur übernimmt dann zusätzlich die Überprüfung der Integritätsbedingungen. Das Konzept der Chimera-Trigger ist, wie auch das Konzept der ChimeraIntegritätsbedingungen, wesentlich mächtiger als das Triggerkonzept, welches von Oracle8 zur Verfügung gestellt wird. Dies liegt unter anderem daran, daß in Chimera mehr Ereignistypen zur Verfügung stehen, durch die ein Trigger ausgelöst werden kann. Die Trigger von Oracle8 können nur durch spezifizierte Ereignisse vom Typ "insert", "delete" und "update" ausgelöst werden. Da diese Ereignisse auch als Auslöser in Chimera-Triggern festgelegt werden können, wäre es sinnvoll diese Trigger direkt durch die entsprechenden Oracle-Trigger zu implementieren. Dadurch würde der Verwaltungsaufwand für diese Trigger vom DBMS übernommen. Zu beachten ist bei dieser Vorgehensweise, daß in Oracle8 nicht mehrere Datenbanktrigger des gleichen Typs einer Tabelle zugeordnet werden dürfen. Aus diesem Grund ist es zu empfehlen diese Trigger als interne Prozedur in Oracle zu implementieren und nur den Aufruf der internen Prozeduren in den entsprechenden Oracle-Trigger zu verlagern. 122 Inhaltsverzeichnis Die Umsetzung von Chimera-Triggern, die durch andere Ereignistypen ausgelöst werden, kann durch den Einsatz von internen Prozeduren und Funktionen in Oracle erfolgen. Im Gegensatz zu den bereits vorgestellten Ereignistypen, existieren keine entsprechenden OracleTrigger die ihren Aufruf automatisch ermöglichen. Deshalb müssen zusätzliche administrative Konzepte eingeführt werden, um die Umsetzung dieser Trigger zu ermöglichen. Der im folgenden vorgestellte Ansatz zur Übersetzung von Triggern orientiert sich im an der Implementation des CPTPhx, welches ähnliche administrative Konzepte benötigt, um das Triggerkonzept von Chimera umzusetzen. Bei der Implementierung durch interne Prozeduren muß in für jeden Trigger eine Prozedur pro Ereignistyp definiert werden. Die Verwaltung dieser Trigger erfolgt mit Hilfe von mehreren Tabellen. Die erste Tabelle dient dazu, alle Ereignisse zu registrieren, die in der Datenbank eintreten können. Das bedeutet, daß jede Anfrage- und DML-Operation durch einen Eintrag in dieser Tabelle registriert werden müßte. Dies könnte durch eine zusätzliche "insert"-Operation in die Ereignistabelle nach der Übersetzung einer Operation erfolgen. Des weiteren ist das Auslösen eines Triggers auch wieder ein Ereignis, daß in der Ereignistabelle registriert werden muß. Um diese Registrierung durchzuführen, müßte jede OracleProzedur, die einen Trigger realisiert, am Ende ihres Programmcodes eine zusätzliche "insert"-Operation durchführen, welche die entsprechenden Daten in die Ereignistabelle einträgt. Diese Ereignistabelle müßte wie folgt aussehen: Ereignis ID Ereignistyp Objektklasse Das erste Attribut der Ereignistabelle dient dazu, daß Ereignis eindeutig zu identifizieren, da innerhalb einer Transaktion mehrere Ereignisse des gleichen Typs auftreten können. Das zweite Attribut wird verwendet, um den Ereignistypen zu speichern, der einen Trigger auslösen kann. Das dritte Attribut beinhaltet den Namen der Tabelle (Objektklasse), in der das Ereignis aufgetreten ist, damit der richtige Trigger zu der entsprechenden Tabelle ausgeführt werden kann. In einer weiteren Tabelle können die "immediate"- und "deferred"Trigger des Datenbankschemas wie folgt verwaltet werden: Triggername Triggertyp Ereignistyp Objektklasse Prozedurname Das erste Attribut der Tabelle zur Verwaltung von Triggern beinhaltet den Triggernamen, der den Trigger innerhalb des Datenbankschemas eindeutig identifiziert. Das zweite Attribut beinhaltet den Triggertypen, der entweder "immediate" oder "deferred" sein kann. Das dritte Attribut beinhaltet das spezifizierte Ereignis, welches den Trigger auslösen soll. Das vierte Attribut beinhaltet die Objektklasse, zu welcher der Trigger gehört und das fünfte Attribut beinhaltet den Namen der internen Oracle-Prozedur, die aufgerufen werden soll, wenn das spezifizierte Ereignis des Triggers eingetreten ist. Diese Daten müssen einmal bei der Schemaübersetzung mitgeneriert werden und dürfen danach nicht verändert werden, da ansonsten die Gefahr besteht, daß sie nicht mehr dem Schema entsprechen. Die Auswertung der Daten, die sich in diesen zwei administrativen Tabellen befinden, erfolgt zu zwei unterschiedlichen Zeitpunkten. Am Ende einer Transaktionszeile muß überprüft werden, ob Ereignisse eingetreten sind, die in "immediate"-Triggern als auslösende 123 Inhaltsverzeichnis Ereignisse spezifiziert worden sind. Dies kann durch den Aufruf einer Oracle-Prozedur erfolgen, welche die Überprüfung in Form einer "select"-Operation vornimmt und das Ergebis in einem Cursor verwaltet. Die select-Operation könnten aufgrund der vorgestellten administrativen Tabellen wie folgt aussehen. SELECT FROM WHERE AND AND T.Prozedurname Ereignistabelle E, Triggertabelle T E.Ereignistyp = T.Ereignistyp E.Objektklasse = T.Objektklasse T.Triggertyp = 'immediate'; Bestandteil des Ergebnis dieser "select"-Operation müssen auf jeden Fall die Namen der internen Oracle-Prozeduren sein, durch welche die auszulösenden Trigger implementiert werden. Alle selektierten Prozeduren werden nacheinander durch den Oracle-Befehl "EXECUTE" abgearbeitet. Der zweite Zeitpunkt zur Auswertung der administrativen Tabellen findet am Ende einer kompletten Transaktion statt. An dieser Stelle müssen alle "deferred"-Trigger auf gleiche Weise wie die "immediate"-Trigger überprüft werden. Die Daten der administrativen Tabelle zu Verwaltung von Ereignissen müssen nach jeder Transaktion vollständig gelöscht werden, damit Trigger innnerhalb der folgenden Transaktion nicht fälschlicher Weise ausgelöst werden. 124 Inhaltsverzeichnis Andrea Scheuber und Michael Horn 10 Literaturverzeichnis [Asc96] Elmar Ascheid: "Ein Werkzeug zur Unterstützung von Entwurf und Validierung deduktiver Regeln in Chimera". Diplomarbeit am Institut für Informatik III, Rheinische-Friedrich-Wilhelms-Universität, Dezember 1996 [CF97] Stefano Ceri und Piero Fraternali: "Designing Database Applications with Objects and Rules – The IDEA Methodology". Addison-Wesley, 1997 [CM93] Stefano Ceri und Rainer Manthey: "Consolidated Specification of Chimera (CM and CL)". ESPRIT Projekt 6333, IDEA.DE.2P.006.01, Oktober 1993 [CM94] W. F. Clocksin und C. S. Mellish: "Programming in Prolog". 4. Auflage, Springer-Verlag, 1994 [Dau96] Ulrich Daugs: "Entwurf und Implementierung einer grafischen Oberfläche zur Verwaltung objektorientierter Datenbank-Schemata". Diplomarbeit am Institut für Informatik III, Rheinische-Friedrich-Wilhelms-Universität, August 1996 [DG94] Susanne Deiters und Ulrike Griefahn: "Propagation Rule Compiler: Tool Specification". ESPRIT Projekt 6333, IDEA.DE.22.O.001, November 1994 [Dra93] Christof Draxler: "A DCG Implementation of the Full Chimera Language". ESPRIT Projekt 6333, IDEA.DD.2P.008.01, 1993 [DS97] Dave Ensor und Ian Stevenson: "Oracle8 Design Tips". O'Reilly, 1997 [ECRC95] "ECLiPSe 3.5: User Manual". ECRC, Dezember 1995 125 Inhaltsverzeichnis [GL96] Ulrike Griefahn, Thomas Lemke: "Implementing Chimera on Top of an Active Relational Database System". ESPRIT Projekt 6333, IDEA.WP22.O.005, Juli 1996 [GLM96] Ulrike Griefahn, Thomas Lemke und Rainer Manthey: "Chimera Prototyping Tool: User Manual". ESPRIT Projekt 6333, IDEA.DE.22.O.006, Mai 1996 [GLM97] Ulrike Griefahn, Thomas Lemke und Rainer Manthey: "Tools for Chimera: An Environment for Designing and Prototyping Advanced Applications in an active DOOD Model". Proc. 1st East-European Symposium on Advances in Databases and Information Systems (ADBIS97), St. Petersburg, September 1997 [GM95] Ulrike Griefahn und Rainer Manthey: "Propagation Rule Compiler: Tool Description". ESPRIT Projekt 6333, IDEA.DE.22.O.003, November 1995 [GR96a] Ulrike Griefahn und Thomas Rath: "Propagation Rule Compiler: Technical Documentation". ESPRIT Projekt 6333, IDEA.DE.22.O.005, November 1996 [GR96b] Ulrike Griefahn und Thomas Rath: "Propagation Rule Compiler: User Manual". ESPRIT Projekt 6333, IDEA.WP.22.O.004, November 1996 [Inf93] "Duden Informatik: Ein Sachlexikon für Studium und Beruf". 2. Auflage, Duden-Verlag, 1993 [KE99] Alfons Kemper und André Eickler: "Datenbanksysteme: Eine Einführung". 3. Auflage, Oldenbourg Verlag, 1999 [Kol95] Thomas H. Kolbe: "Anbindung des RDBMS Oracle an ECLiPSe". Institut für Informatik III, Rheinische-Friedrich-Wilhelms-Universität, September 1995 [Lem94] Thomas Lemke: "The Schema Evolution Assistant: Tool Specification". ESPRIT Projekt 6333, IDEA.DE.22.O.002, November 1994 [LM95] Thomas Lemke und Rainer Manthey: "The Schema Evolution Assistant: Tool Description". ESPRIT Projekt 6333, IDEA.DE.22.O.004, November 1995 [LM97] Thomas Lemke und Rainer Manthey: "The Passive Rule Design Tool: Tool Documentation" ESPRIT Projekt 6333, IDEA.DE.22.O.010, März 1997 [Ora98] Online Dokumentation zu Oracle8, Oracle Corporation, 1998 [Schi98] Michael Schiefer: "CARDT- Ein Tool zur dynamischen Analyse aktiver Regeln". Diplomarbeit am Institut für Informatik III, Rheinische-FriedrichWilhelms-Universität, Oktober 1998 [Schm99] Thomas Schmitt: "Entwurf und Implementation einer graphischen Schnittstelle zur Datenmanipulation für das objektorientierte Datenmodell Chimera". Diplomarbeit am Institut für Informatik III, Rheinische-Friedrich-WilhelmsUniversität, Januar 1999 126 Inhaltsverzeichnis [Schu99] Stefan Schubert: "Ein Passiv Rule Prototyping Tool für Chimera". Diplomarbeit am Institut für Informatik III, Rheinische-Friedrich-Wilhelms-Universität, Juli 1999 127