1 Übersicht OpenIngres-Komponenten Übersicht OpenIngres

Werbung
Skript zur Vorlesung Datenbanken VertiefungSeite 1
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
1 Übersicht OpenIngres-Komponenten
CA-OpenIngres ist ein auf SQL-92 basierendes Relationales Datenbank Management System (RDBMS), welches zusätzlich zu den eigentlichen Datenbankfunktionen eine Reihe von einfach zu benutzenden Werkzeugen zur
Abfrage bis hin zur Entwicklung komplexer Anwendungssysteme besitzt
(Database Front Ends).
Neben dem visuellen Zugriff auf eine Datenbank über sog. Frames enthält
OpenIngres jetzt eine vollständige Implementierung von SQL-92 (Entry Level
+ Erweiterungen).
Daneben bietet Ingres mit Ingres/4GL und OpenROAD (früher Windows4GL)
vollständige Anwendungsentwicklungssprachen der 4. Generation an (zeichenorientiert und mit graphischer Oberfläche). Zeichenorientierte Programmgeneratoren erleichtern die Entwicklung von Datenbankanwendungen
weiter.
Weiterhin unterstützt Ingres verteilte Datenbanken.
Ingres (Interactive Graphics and Retrieval System) stammt aus einem Projekt an der Universität von Kalifornien in Berkeley (Michael Stonebraker und
Eugene Wong, 1973-1975). Ergebnisse waren neben der eigentlichen relationalen Datenbank mit 5 Zugriffsmethoden die Datenbanksprache QUEL
(Query Language). Betriebssystem war Unix.
Seit 1979 wird Ingres kommerziell vermarktet (Fa. RTI, Relational Technology Incorporated). Konversion von Unix nach VMS. Später wurde Ingres von
der Firma ASK übernommen, 1994 dann von CA.
Im Laufe der Zeit kamen die folgenden Komponenten hinzu
• QBF: Query by Forms
• Graph: für graphische Darstellungen
• RBF: Report by Forms
• ABF: Application by Forms
Stärke im Bereich verteilter Datenbanken:
• Ingres/NET: Client/Server Technologie
• Ingres/STAR: Verteilung der Daten im Netz
• Multiserver-Architektur: Dynamische Zuweisung zwischen Front-Ends
und Back-Ends (Datenbank-Servern)
Anfang 1990
• Knowledge-Management Komponente
• Object-Management Komponente
• Windows4GL: Graphische Benutzeroberfläche für Datenbankanwendungen
1995
• SQL-92 basiertes OpenIngres
• Verbessertes Windows4GL: OpenROAD
Skript zur Vorlesung Datenbanken VertiefungSeite 2
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
1.1
Ingres-Datenbank
Ingres besteht aus zwei Hauptbestandteilen:
• Ingres Benutzerschnittstelle (User Interface)
• Ingres Data Manager
Startet man eine Benutzerschnittstelle, so wird man automatisch zu einem
Data Manager Prozeß verbunden.
Client/Multi-Server Architektur:
Client1
Client2
Client3
Ingres
Tools und Applications
Ingres
Tools und Applications
Ingres
Tools und Applications
Ingres/Net
Ingres/Net
Ingres/Net
Ingres/Net
Ingres/Net
Ingres
Data
Manager
Ingres
Data
Manager
Ingres
Database
Ingres
Database
Server1
Server2
Die eigentliche Datenbank speichert dabei
• Daten (Data Management)
• Regeln (Knowledge Management) und
• Objekte (Object Management).
Sie besteht u.a. aus einem Query Optimizer und dem Data Dictionary.
Besonderheiten: Unterstützung von
• Kompilierten Datenbankprozeduren (in Ingres 4GL oder SQL) für sich
wiederholende Transaktionen
• Verschiedenen Methoden zur Performance-Steigerung (Fast Commit,
Group Commit, Multiblock-Lese- und Schreiboperationen).
Skript zur Vorlesung Datenbanken VertiefungSeite 3
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Optionales Knowledge-Management unterstützt
• Regelsystem zur Einhaltung von Geschäftsregeln und Regeln zur referentiellen Integrität. Formuliert in Ingres 4GL oder SQL. Mit werteabhängiger Aktivierung.
• Alarmsignal für Datenbankereignisse (Database Event Alerts): Aufruf
von Anwendungen auf bestimmte Ereignisse hin (z.B. Nachbestellung,
Erinnerungsschreiben).
• Ressourcen-Kontrolle in Verbindung mit dem Query-Optimizer
• Zugriffs-Kontrolle
Optionales Object-Management unterstützt
• Definition eigener Datentypen anstelle der Standard Datenbankdatentypen (Zahlen, Zeichen, ...), z.B. nichtmetrische Maße, Koordinatenpaare, Vektoren, Bitmaps
• Manipulation dieser neuen Datenobjekte mittels neuer Operatoren und
Funktionen (diese auch für Standard-Datentypen)
Weitere Komponenten:
• Ingres/Gateways: Zugriff auf Nicht-Ingres Datenbanken (Rdb und RMS,
DB2 und IMS, ALLBASE/SQL).
• Ingres/STAR: Zugriff auf mehrere Datenbanken gleichzeitig.
Achtung: Unterscheidung: Mehrere Tabellen in einer Datenbank vs. mehrere
Datenbanken. Eine Datenbank ist immer eine Kollektion von mehreren Tabellen. Diese müssen nicht unbedingt einen inhaltlichen Zusammenhang
haben (sollten aber).
1.2
Visueller Zugriff und Programmie
Programmierung
Die Anwenderschnittstelle von Ingres unterteilt sich in Komponenten,
• die auch von einem Endbenutzer verwendet werden können (menügetriebenes, visuelles System) und
• solche zur Anwendungsentwicklung.
Mit Hilfe der menügetriebenen, visuellen Werkzeuge ist das Erstellen von
Tabellen und Dateneingabe oder -abfragen leicht zu formulieren, ebenso
Verknüpfungen von Tabellen. Dies funktioniert auch alles mit reinen zeichenorientierten Terminals und ohne den Einsatz einer konkreten Abfragesprache. Selbst Anwendungen können so erstellt werden.
Zusätzlich wird SQL als Abfragesprache unterstützt, hinzu kommt noch Ingres/4GL sowie das objektorientierte, graphische OpenROAD zur Anwendungsentwicklung.
Skript zur Vorlesung Datenbanken VertiefungSeite 4
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Das Ingres User Interface:
Query
by
Forms
Visuals
Forms
E ditor
Application
by Forms
ABF
Ingres
Datenbank
Ingres
Vision
Ingres
Windows
4GL
SQL
Terminal
Monitor
Report
by
Forms
Ingres
M enu
1.3
Datenbanksprache SQL
Basiert auf dem relationalen Datenbankmodell. Ursprünglich Abkürzung für
Structured Query Language. Aus dem Entwicklungsprojekt System R der
IBM hervorgegangen (1974-1979). Vorgänger von SQL war die Sprache
SEQUEL.
Erste Implementierungen bei Oracle (1980), dann SQL/DS und später DB2
(IBM). Erst 1985 für Ingres implementiert. Im Oktober 1986 als ANSIStandard übernommen. Moderate Erweiterungen geschahen 1989 (SQL-89).
Eine umfangreiche Erweiterung des ANSI-Standards (SQL2 bzw. SQL-92) ist
gerade verabschiedet worden. ⇒ OpenIngres
Zur Zeit wird schon wieder an SQL3 gearbeitet.
Einzelheiten in einem späteren Kapitel.
1.4
Zugriff auf eine Ingres Datenbank
Generelle Syntax zum Aufruf von Ingres Komponenten aus einer Unix-Shell
heraus:
kommando [v_node::]dbname
Um auf eine Datenbank auf einem anderen Knoten (Rechner) zugreifen zu
können, muß natürlich Ingres/NET installiert sein und man muß den
v_node Namen dieses Rechners wissen.
Der Ingres System Administrator hat mit Hilfe des netu Programms diesen
Namen definiert.
Skript zur Vorlesung Datenbanken VertiefungSeite 5
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Ebenfalls mit Hilfe von netu muß die Zugangsberechtigung auf den Datenbank-Knoten definiert werden.
Bestimmte Kommandos sind nicht über das Netzwerk aufrufbar. Dazu gehören createdb, accessdb und rollforwarddb.
1.5
Erstellen einer Datenbank
Erzeugen der Datenbank mit createdb, Vergabe von Zugriffsrechten durch
accessdb. Beide müssen auf dem Datenbankserver laufen.
Beispiel: Der User ingres ist auf dem Datenbankserver eingeloggt. Auch der
Benutzer i123 sei berechtigt, Datenbanken zu erzeugen.
createdb -ui123 -p dbv95_einname
Dies erzeugt eine „private“ Datenbank. Der User i123 ist DBA und zunächst
der einzige Nutzungsberechtigte der Datenbank.
Als nächstes muß das Nutzungsrecht für einen weiteren Benutzer gegeben
werden.
accessdb
Dieses Utility ist Frame-orientiert.
Selektiere Database. Es erscheint der Prompt
Database:
Eingabe des Datenbanknamens, z.B. dbv96_einname.
Wähle Authorized Users und gib den/die login-Namen des/der zu authorisierenden User ein.
Selektiere Save, dann Quit.
Skript zur Vorlesung Datenbanken VertiefungSeite 6
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
2 Zugriff über Forms und Menus
Wichtiger Begrif bei Ingres: Das Frame. Kombination aus Maske und Menüs.
Voraussetzung für das korrekte Funktionieren in vielfältigen Rechnerumgebungen: Definition des richtigen Terminaltyps.
setenv TERM_INGRES terminalname
terminalname ist
Sun OS
sunf
Sun OS, OpenWindows
sun-cmdf
HP-UX
hpterm
Wird üblicherweise beim Einloggen (nach Abfrage) in .cshrc automatisch
durchgeführt.
2.1
IngMenu
Aufruf durch
ingmenu dbname
Haupt-Frame als Menü zu allen Front-End Komponenten mit Funktionenaufruf.
Database: xyz
INGRES/MENU
Tables
Forms
JoinDefs
Reports
Applications
Queries
Create/examine tables or query/report on table data
Create/edit/use forms for customized data access
Create/edit/use join definitions on multiple tables
Create/edit/run reports
Create/edit/run Vision and ABF applications
Query data using Query-By-Forms or a query language
Place the cursor un your choice and press „Select“
Select Shell
Help
End
Quit
Unterpunkte:
• Tables
Erzeugen, ändern, abfragen, Abfrage von Informationen über Tabellen
Skript zur Vorlesung Datenbanken VertiefungSeite 7
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Forms
Erzeugen, editieren, benutzen von selbstdefinierten Forms
• JoinDefs
Erzeugen, editieren, benutzen von Join-Definitionen zur Verknüpfung
mehrerer Tabellen
• Reports
Erzeugen, editieren, ausführen von Reports
• Applications
Erzeugen, ändern, ausführen von 4GL-Anwendungen, ABF: Application
by Forms
• Queries
Abfragen mittels Query-by-Forms (QBF) oder SQL
Selektion durch Positionierung des Cursors und Enter bzw. GO.
Sonstige Bedienung durch Funktionstasten.
Springen von Form zur Menüleiste durch den Menu Key. Abhängig vom Terminaltyp (Sun OpenWindows: R1, HP-UX: F6). Geht das Menü über die Frame-Breite hinaus, so erreicht man die anderen Teile durch mehrfaches
Drücken des Menu Key. Man kann Funktionen aus der Menü-Zeile auch
durch Eingabe des Namens wählen. Zurück zur Form mit Return Key.
Spezielle Key-Funktionen:
Tab
Control-P
Return
Control-E
Cursor auf nächstes Feld oder nächste Spalte
Cursor auf voriges Feld oder vorige Spalte
Cursor auf nächstes Feld und gleichzeitig werden alle Daten bis
zum Ende des aktuellen Feldes gelöscht.
In Table Fields geht Cursor zur nächsten Spalte bzw. nächsten
Zeile, wenn in letzter Spalte
Toggle Insert und Overstrike Mode
Help Key ist bei OpenWindows auf R2 gemapped. Konflikt mit OpenWindows-Zuordnung. Abhilfe: Shift R2 benutzen!
2.2
Tabellen
2.2.1 Erzeugen von Tabellen
Sobald man Zugriff auf eine Datenbank hat, kann man dort in der Regel Tabellen anlegen. Beim Anlegen einer Tabelle muß man die Felder (Attribute)
der Tabelle definieren. Dazu gehören Name und Datentyp. Als StandardDatentypen gibt es in Ingres die folgenden:
• c(n)
String fester Länge von maximal 2000 druckbaren ASCII-Zeichen. Nicht
druckbare Zeichen werden zu Blanks konvertiert. Blanks werden bei
Vergleichen ignoriert. Kompatibilität zu früheren Versionen.
• char(n)
String fester Länge von maximal 2000 druckbaren oder nichtdruckba-
Skript zur Vorlesung Datenbanken VertiefungSeite 8
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ren ASCII-Zeichen. Bei Vergleich wird der kürzere String mit Blanks
aufgefüllt. Kompatibel zu dem gleichnamigen Typ in ANSI SQL. Ebenfalls feste Länge.
• text(n)
String variabler Länge von maximal 2000 ASCII (extended) Zeichen außer NULL. Kürzerer (sonst gleicher) String ist kleiner als längerer. Kompatibilität zu früheren Versionen.
• varchar(n)
String variabler Länge von maximal 2000 ASCII (extended) Zeichen. Alle
Zeichen sind erlaubt, auch NULL. Bei Vergleich wird der kürzere String
mit Blanks aufgefüllt. Kompatibel zu dem gleichnamigen Typ in ANSI
SQL.
• integer1
1 byte integer -128 .. +127
• integer2 oder smallint
2 byte integer -32 768 .. +32 767
• integer4 oder integer
4 byte integer
• float4
4 byte floating point 8.43 ⋅10-37 .. 3.37 ⋅1038
• float8
8 byte floating point 4.19 ⋅10-307 .. 1.67 ⋅10308
• date
Sog. „abstract data type“ (bei Ingres). 12 Bytes.
Datum, Zeit oder Zeitintervall, formatierbar über Environment-Variable
(II_DATE_FORMAT)
• money
Sog. „abstract data type“ (bei Ingres). 8 Bytes.
Geldzahlenwerte, formatierbar über Environment-Variable
(II_MONEY_FORMAT („$“), II_DECIMAL („.“ oder „,“) und
II_MONEY_PREC(2)).
II_DATE_FORMAT:
Default Eingabe-Datumsformate sind:
dd-mmm-yyyy
auch Ausgabeformat
mm/dd/yy
mmddyy
Wird
setenv II_DATE_FORMAT GERMAN
gesetzt, so ist auch das Eingabeformat
dd.mm.yy
möglich (Ausgabe ???).
II_MONEY_FORMAT:
Beispiele:
Skript zur Vorlesung Datenbanken VertiefungSeite 9
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
setenv II_MONEY_FORMAT L:$
→ $100
setenv II_MONEY_FORMAT T:DM
→ 100DM
setenv II_MONEY_FORMAT 'T: FF' → 100 FF
Null-Wert ist ein bestimmter Wert eines Attributs, der besagt, daß dem Attribut (noch) kein Wert zugewiesen wurde: Nicht-initialisierter Wert. Ungleich
dem Zahlenwert Null oder der ASCII 0!
Sind Null-Werte erlaubt, so enthalten nicht-initialisierte Felder diesen speziellen Wert. Sind Null-Werte nicht erlaubt, so muß man in dem Default-Feld
angeben, ob Defaults (0, Leerstring) für nicht ausdrücklich initialisierte Felder eingesetzt werden sollen („y“). Ist die Eingabe hier „n“, so muß das Feld
immer einen Wert zugewiesen bekommen.
Keys und Indexes sollen uns zunächst noch nicht interessieren.
TABLES - Create a Table
Enter the name of the new table:
Enter the column specification for the new table:
Column Name
Insert
Delete Blank
Data Type Key # Nulls
Move
GetTableDef
Defaults
ListChoices Help Cancel
Sichern der Eingaben mit Save!
2.2.2 Ändern von Tabellen
Ab OpenIngres 2.0: Siehe hierzu den SQL-Befehl Alter Table!
Die Struktur einer Tabelle kann nur noch mit etwas Mühe geändert werden.
Nehmen wir an, wir haben die (leere) Tabelle A:
1. Erzeuge eine neue Tabelle B
2. Kopiere mit GetTableDef die Struktur von A nach B
3. Führe die notwendigen Änderungen an der leeren Tabelle B durch
4. Speichere die Definition von B
5. Lösche A mit dem Befehl Destroy
6. Benenne B nach A um:
Skript zur Vorlesung Datenbanken VertiefungSeite 10
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Erzeuge Tabelle A
• Hole Struktur von B mittels GetTableDef
• Speichere A
• Lösche B
Enthält die umzustrukturierende Tabelle bereits Daten, so hilft nur das
Entladen der Tabelle via SQL (bulk Copy) und das neue Laden der umstrukturierten Tabelle.
2.3
Nützliche Utilities
catalogdb
Auflistung
• aller für den Benutzer zugreifbaren Datenbanken,
• die dem System bekannten location Namen,
• Benutzer Rechte.
createdb
Kreiert eine neue Datenbank auf dem jetzigen Knoten. Man benötigt entsprechende Rechte. Der Erzeuger der datenbank wird der Database Administrator (DBA) für diese Datenbank.
destroydb
Löscht eine Datenbank mit allen zugehörigen Komponenten (Tabellen, JoinDefs, Forms, ...). Auch dazu benötigt man natürlich die entsprechenden
Rechte.
2.4
Query by Forms
QBF: Ausfüllen eines Formulars zur Definition der Abfrage (ähnlich wie
Query by Example – QBE). Resultate stehen danach in dem Formular.
2.4.1 Einfache Datenmanipulation
Alle Datenzugriffe werden bei Ingres Query genannt, auch das Hinzufügen
von neuen Datensätzen.
Aufruf über ingmenu und Query, dann Unterpunkt QBF.
QBF arbeitet in zwei Phasen:
• Definition phase: Festlegung der Daten, die gesucht, geändert oder
eingefügt werden sollen
• Execution phase: Ausführung der Operationen (Append, Retrieve oder
Update)
Objekt der Abfrage können sein:
• Tables
Einfache Tabellen oder Views
• JoinDefs
Zwei oder mehrere verknüpfte Tabellen (Joins)
• QBFnames
Eine benutzerdefinierte Form (Maske), die mit einer Tabelle oder einer
JoinDef verknüpft ist.
Skript zur Vorlesung Datenbanken VertiefungSeite 11
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
In der execution phase kann man die folgenden Operationen mit dem selektierten Objekt durchführen:
• Append: Hinzufügen von Datensätzen
• Retrieve: Ansehen von Datensätzen
• Update: Ändern von Datensätzen
Ingres unterscheidet in Forms zwischen
• Simple fields: Einfache Felder in der Form. Jede Form zeigt einen Satz
(Reihe) der Tabelle
und
• Table fields: Tabellarische Felder (mehrere Reihen einer Tabelle)
Nach dem Hinzufügen neuer Sätze darf man den Aufruf von Append nicht
vergessen. Sonst werden die Sätze nicht wirklich hinzugefügt.
Bei der Retrieve-Operation füllt man einzelne Felder der Form mit Suchmustern aus. Die Ausführung liefert dann keinen, einen Satz oder mehrere Sätze als Ergebnis.
Suchmuster
Bedeutung
Blank
Alle Sätze
Exakter Inhalt
Satz mit genau diesem Muster
*
0 oder mehrere beliebige Zeichen
?
genau ein beliebiges Zeichen
[aAbB] oder [A-D]
Eines der Zeichen oder des Zeichenbereiches in den
eckigen Klammern
Die Wildcards können nur mit Character-Daten benutzt werden.
Es können auch Vergleichsoperationen vorkommen:
Operator
Bedeutung
>
größer als
<
kleiner als
>=
größer oder gleich
<=
kleiner oder gleich
!=
ungleich
or
Oder-Verknüpfung
and
Und-Verknüpfung
Skript zur Vorlesung Datenbanken VertiefungSeite 12
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Bedingungen für eine Spalte können noch mit and oder or verknüpft werden.
and kann dabei durch ein Leerzeichen ersetzt werden. Will man Leerzeichen
als Bestandteil von Suchstrings angeben, so muß der String in Anführungszeichen eingeschlossen werden.
Klammerung ist möglich. String-Vergleiche sind case-sensitiv!
Bedingungen für Spalten in einer Zeile werden und-verknüpft, Bedingungen
für Spalten in untereinander stehenden Zeilen (nur bei Table field möglich)
werden oder-verknüpft.
Die Ergebnisse können über Aufruf von Order auch sortiert werden.
2.4.2 Komplexe Datenmanipulation
Verknüpfung von Tabellen mit JoinDefs zur Vorbereitung von Abfrage mehrerer Tabellen.
Aufrufen von JoinDefs aus ingmenu. Dann Create.
Zwei Arten von Joins (Angabe unter Role):
• Master to master: Relationale equi-joins, eins-zu-eins
• Master to detail: eins-zu-viele.
Joins können auch verkettet werden. Sie können jedoch nur eine Master/Detail Definition enthalten.
Ein Join mit zwei Tabellen:
Employee Table
Gemeinsame Werte in einer
JOIN Spalte
Ref
1224
Name
Address
Anne Jones 44 Peabody Flats London
Project Tasks Table
Task ID
Dev 12
Task ID
Dev 12
Task Name
Produce Sales
Year End Report
Ref
1224
Task Name
Produce Sales Year End Report
Ref
1224
Name
Anne Jones
Nach Auswahl der zu verknüpfenden Tabellen und ihrere Rollen (man kann
ihnen noch abgekürzte Namen geben), müssen die Verknüpfungsspalten definiert werden. Dazu ruft man den Menüpunkt Joins auf.
Unter dem weiteren Menüpunkt Rules kann man nun bereits hier einfache
Regeln zur Wahrung der referentiellen Integrität angeben.
Skript zur Vorlesung Datenbanken VertiefungSeite 13
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
QBF - JoinDef Update & Delete Rules
Update Information: To enable modification of join fields in UPDATE mode, enter „Yes“ under Update? Column
Column
Update?
abteilung.abt_nr
mitarbeiter.abt_nr
no
yes
Delete Information: To disable deletion of rows in table during UPDATE
mode, enter „No“ under Delete? Column
Role
Table Name (or Abbreviation)
Delete?
MASTER
DETAIL
abteilung
mitarbeiter
no
yes
Joins
Forget Help End
In dem ersten Block kann man angeben, ob Änderungen in der Join-Spalte
der beiden Tabellen erlaubt sind. Durch geschickte Angabe kann man z.B.
spezifizieren, was mit dem anderen Feld geschehen soll, wenn das eine geändert wird: Ebenfalls ändern oder nicht.
In dem zweiten Block entscheidet man, ob das Löschen der Sätze der verknüpften Tabellen erlaubt ist oder nicht. Also z.B. ob beim Löschen eines
Satzes der einen Tabelle auch der/die entsprechenden Sätze der anderen
Tabelle gelöscht werden sollen.
Durch Aufruf von ChangeDisplay kann man zusätzlich angeben, daß bestimmte Spalten nicht angezeigt werden sollen.
Durch Aufruf von Go kann man die neu definierte JoinDef sofort ausführen
dabei überprüfen.
Nicht vergessen, mit Save zu sichern!
Skript zur Vorlesung Datenbanken VertiefungSeite 14
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
3 Einstieg in SQL
SQL besteht aus mehreren Untergruppen:
• Data Definition Language (DDL)
Kreieren, Modifizieren und Löschen von Tabellen, Erzeugen von Indizes
• Data Manipulation Language (DML)
Abfrage-Sprache sowie Eingabe, Modifikation und Löschen von Tabellen-Reihen
• Definition von Views (Teil von DDL)
• Authorisierung (Teil von DDL)
Zugriffsrechte auf Tabellen und Views
• Integrität
In SQL-89 nur limitierte Form der Integritätsüberprüfung, in SQL-92
mehr
• Transaktionskontrolle
Spezifikation des Anfangs (implizit) und des Endes einer Transaktion
3.1
Datendefinition
Grundsätzlich muß zunächst eine Datenbank definiert werden:
createdb MeineDatenbank
Dann kann man in den SQL-Editor gehen und Tabellen kreieren. Zwei Formen der Anweisung:
CREATE TABLE TabName(SpaltenName1 SpaltenTyp1
[,SpaltenName2 SpaltenTyp2, ..])
[WithKlausel];
oder
CREATE TABLE TabName(SpaltenName1 SpaltenTyp1
[,SpaltenName2 SpaltenTyp2, ..])
AS SelectAnw
[WithKlausel];
Tabellennamen dürfen bei Ingres nicht mit „ii“ beginnen (reserviert für interne Zwecke).
Mögliche Datentypen sind
Numerisch:
• integer (4 Bytes, ≡ integer4),
• smallint (2 Bytes, ≡ integer2),
• integer1,
• decimal,
• float (8 Bytes, ≡ float8),
• float4 (4 Bytes, ≡ real)
Character, feste Länge
• c
Skript zur Vorlesung Datenbanken VertiefungSeite 15
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• char (≡ character)
Character, variable Länge
• text
• varchar
• long varchar
Abstract
• date
• money
• object_key
• table_key
Binär
• byte
• byte varying
• long byte
Beispiele für DATE Formate:
Absolute Angabe:
28-may-1993
28-may-1993 07:58:00
Zeitintervall:
10 yrs 9 mon 8 days 7 hrs 6 mins 55 secs
Logical Key Data Types
Dazu gehören object_key und table_key. Haben datenbankweiten oder tabellenweiten eindeutigen Wert. Z.B. für Primärschlüssel.
Können system_maintained oder not system_maintained sein. Bei system_maintained erzeugt Ingres selbst eindeutige Werte. Dann ist dieser
Wert nicht mehr änderbar. Auch Probleme beim Kopieren und Ändern von
Datenbanken. Alle Varianten sind nicht zu empfehlen!!
Die Datentypen können noch weiter qualifiziert werden:
• [ [ WITH ] DEFAULT default_spec | WITH DEFAULT | NOT DEFAULT ]
• [ WITH NULL | NOT NULL ]
• [ [ CONSTRAINT constraint_name ] column_constraint
{, [ CONSTRAINT constraint_name ] column_constraint } ]
Dabei kann column_constraint einer oder mehrere der folgenden Punkte sein:
• unique
• primary key
Skript zur Vorlesung Datenbanken VertiefungSeite 16
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• REFERENCES table_name [ (column_name) ]
• CHECK (check_specification)
Default-Spezifikation:
• not default
Wert für diese Spalte muß vorliegen
• with default
ohne Wert setzt DBMS ein: 0 für numerische und money-Felder,
leerer String für Character und date
• [ with ] default default_spec
ohne Wert setzt DBMS den angegebene Default-Wert ein. Muß typkompatibel sein.
Für Character-Spalten ist zusätzlich erlaubt: „user“, „current_user“,
„system_user“
Möglichkeit von NULL-Werten:
• with null
Default. Ohne Wert, nimmt Spalte den NULL-Wert an.
• not null
Ohne Default-Spezifikation muß diese Spalte zwingend Wert zugewiesen
bekommen,
mit Default-Spezifikation wird der Default Wert zugewiesen, falls kein
Wert durch den Benutzer geliefert wird.
Mögliche Kombinationen:
• with null
Die Spalte akzeptiert NULLs. Ohne Wert, nimmt Spalte den NULL-Wert
an.
• with null with default
Die Spalte akzeptiert NULLs. Ohne Wert, nimmt Spalte den DefaultWert an.
• with null not default
Die Spalte akzeptiert NULLs. Der Benutzer muß einen Wert liefern.
• not null with default
Die Spalte akzeptiert keine NULLs. Ohne Wert, nimmt Spalte den Default-Wert an.
• not null not default oder not null
Die Spalte akzeptiert keine NULLs. Der Benutzer muß einen Wert liefern. Typisch für Primärschlüssel.
Constraints:
• unique
Muß in Verbindung mit not null spezifiziert werden: unique not null!
create table dept (dname char(10) unique not null, ...)
Soll die Kombination mehrerer Spalten unique sein, so muß dies auf
Tabellenebene spezifiziert werden.
Skript zur Vorlesung Datenbanken VertiefungSeite 17
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
create table depts(dname char(10) not null,
dlocation char(10) not null,
constraint unique_dept unique (dname, dlocation));
• check Constraint
Benutzerdefinierte Constraints bezüglich einer oder mehrerer Spalten
create table emps (name char(25), sal money,
constraint check_salary check (sal > 0); /* Boolean expr */
Auch für mehrere Spalten:
create table dept(dname char(10), location char(10),
budget money, expenses money,
constraint check_amount check (budget > 0 and
expenses <= budget));
• Referential Constraints
Eine Eingabe wird bezüglich einer Spalte in einer anderen Tabelle (oder
auch derselben Tabelle) validiert: Fremdschlüssel.
create table emp (ename char(10),
edept char(10) references dept(dname));
oder
create table mgr (name char(10), empno char(5), ...,
foreign key (name, empno) references emp);
Hier müssen für emp die beiden Spalten name und empno als primary
key constraint definiert sein.
• Primärschlüssel Constraints
Erlaubt es anderen Tabellen, auf die hier definierten Spalten in referential constraints bezug zu nehmen:
create table partnumbers (partno int primary key, ...);
primary key impliziert die unique und not null Constraints!
Man unterscheidet Column-Level und Table-Level Constraints:
Column-Level Constraint:
create table mytable (name char(10) not null,
id
integer references idtable(id),
age integer check (age>0));
Table-Level Constraint:
create table yourtable (firstname char(20),
lastname char(20),
unique(firstname, lastname));
Wird der Versuch unternommen, eine Tabelle derart zu ändern, daß ein so
definierter Constraint verletzt würde, so wird der gesamte SQL-Befehl abgebrochen und ein Fehler erzeugt.
Skript zur Vorlesung Datenbanken VertiefungSeite 18
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Bemerkung:
Es gibt noch eine create integrity-Anweisung (nicht
ANSI/ISO SQL-92 verträglich).
Weiterhin können rules in Verbindung mit DatenbankProzeduren Integritäten erzwingen.
Spaltendefinition als Syntaxdiagramm:
column definition
datatype
column name
domain
literal
default
datetime
value
function
current_user
session_user
system_user
null
column-constraint
collate-clause
Skript zur Vorlesung Datenbanken VertiefungSeite 19
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Constraints als Syntaxdiagramm (unvollständig!):
not
table constraint
null
unique
constraint
primary key
constraint name
check
references
(
search-condition
table name
(
column name
)
,
Die WithKlausel beschreibt weitere Eigenschaften einer Tabelle, die wir
auch schon von der forms-basierten Tabellenerzeugung kennen:
WITH
LOCATION = (...)
[NO]JOURNALING
[NO]DUPLICATES
Angabe von
• Plattenspeicherbereich für die Tabelle
• Sicherung des ursprünglichen Inhalts aller modifizierten Reihen
• Zulassung identischer Reihen oder nicht
Mit der zweiten Variante (inkl. SELECT-Anweisung) kann man die neue Tabelle mit dem Ergebnis der SELECT-Anweisung z.B. aus einer anderen Tabelle laden.
3.1.1 Erzeugen von Beispiel-Tabellen
Entity-Relationship Modell:
abteilung
projekt
mitarbeiter
arbeiten
)
Skript zur Vorlesung Datenbanken VertiefungSeite 20
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Detaillierteres Modell:
abteilung
mitarbeiter
abt_nr
m_nr
abt_name
stadt
m_name
m_vorname
abt_nr
arbeiten
m_nr
pr_nr
projekt
aufgabe
einst_dat
pr_nr
pr_name
mittel
Hieraus ergibt sich die folgende physikalische Tabellenstruktur:
abteilung
Feld
Typ
Domain Null
Default
abt_nr
char(4)
n
n
abt_name
char(20)
n
n
stadt
char(15)
j
Muenchen
PK
FK zu Tabelle
x
mitarbeiter
Feld
Typ
Domain
Null
Default
m_nr
integer
n
n
m_name
char(20)
n
n
m_vorname
char(20)
n
n
abt_nr
char(4)
n
n
PK
FK zu Tabelle
x
abteilung
projekt
Feld
Typ
Domain Null
Default
pr_nr
char(4)
n
n
pr_name
char(25)
n
n
mittel
float8
j
n
PK
x
FK zu Tabelle
Skript zur Vorlesung Datenbanken VertiefungSeite 21
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
arbeiten
Feld
Typ
Domain
Null
Default
PK
FK zu Tabelle
m_nr
integer
n
n
x
mitarbeiter
pr_nr
char(4)
n
n
x
projekt
aufgabe
char(15)
j
n
einst_dat
date
j
n
Hieraus ergibt sich nun das folgende SQL-Script (DDL):
CREATE TABLE abteilung
(abt_nr
CHAR(4) NOT NULL
CONSTRAINT abt_prim PRIMARY KEY,
abt_name CHAR(20) NOT NULL,
stadt
CHAR(15) WITH DEFAULT 'Muenchen');
CREATE TABLE mitarbeiter
(m_nr
INTEGER NOT NULL
CONSTRAINT mit_prim PRIMARY KEY,
m_name
CHAR(20) NOT NULL,
m_vorname CHAR(20) NOT NULL,
abt_nr
CHAR(4) CONSTRAINT mit_for
REFERENCES abteilung);
CREATE TABLE projekt
(pr_nr
CHAR(4)
NOT NULL
CONSTRAINT pro_prim PRIMARY KEY,
pr_name CHAR(25) NOT NULL,
mittel FLOAT8);
CREATE TABLE arbeiten
(m_nr
INTEGER NOT NULL,
pr_nr
CHAR(4) NOT NULL,
aufgabe
CHAR(15),
einst_dat DATE,
CONSTRAINT arb_prim
PRIMARY KEY (m_nr, pr_nr),
CONSTRAINT arb_for_mit FOREIGN KEY (m_nr)
REFERENCES mitarbeiter,
CONSTRAINT arb_for_pro FOREIGN KEY (pr_nr)
REFERENCES projekt);
Als Voreinstellung werden Tabellen in einer unstrukturierten Speicherstruktur heap erzeugt. Hierbei werden neue Reihen einfach an das Ende angefügt.
Weitere Speicherstrukturen können sein:
• hash
• isam
Zugriff über berechneten Schlüssel
Zugriff über Index
• btree
Zugriff über Baumstruktur
Wir werden diese Speichermodelle später ausführlich besprechen.
Skript zur Vorlesung Datenbanken VertiefungSeite 22
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Das universellste Speichermodell ist btree.
Die Speicherstruktur kann man nach der Tabellenerzeugung ändern:
MODIFY abteilung TO btree UNIQUE ON abt_nr;
MODIFY mitarbeiter TO btree UNIQUE ON m_nr;
MODIFY projekt TO btree UNIQUE ON pr_nr;
MODIFY arbeiten TO btree UNIQUE ON m_nr, pr_nr;
Die hier definierten Tabellen existieren physikalisch. Zusätzlich kann man
quasi virtuelle Tabellen kreieren, sog. Views. Sie werden aus den darunterliegenden physisch vorhandenen Tabellen abgeleitet. Dazu gibt es die Anweisung
CREATE VIEW ...
die den View basierend auf einer SELECT-Anweisung erzeugt. Wie behandeln Views später.
Eine weitere Struktur, die hier zunächst nur erwähnt werden sollte, ist ein
Sekundärindex für andere Felder (nicht Primärschlüssel) einer Tabelle, der
mit
CREATE INDEX ...
erzeugt wird. Auch dazu später.
Die Tabellen werden nun bevölkert:
abteilung
abt_nr
projekt
abt_name
stadt
pr_nr
pr_name
mittel
a1
Beratung
Muenchen
p1
Apollo
120000
a2
Diagnose
Muenchen
p2
Gemini
95000
a3
Freigabe
Stuttgart
p3
Merkur
186500
Skript zur Vorlesung Datenbanken VertiefungSeite 23
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
arbeiten
mitarbeiter
m_nr
pr_nr
aufgabe
einst_dat
m_nr
m_name
10102
p1
Projektleiter
01.10.1988
25348 Keller
Hans
a3
10102
p3
Gruppenleiter
01.01.1989
10102 Huber
Petra
a3
25348
p2
Sachbearbeiter 15.02.1988
18316 Mueller
Gabriele
a1
18316
p2
01.06.1989
29346 Probst
Andreas
a2
29346
p2
15.12.1987
9031 Meier
Rainer
a2
2581
p3
Projektleiter
15.10.1989
2581 Kaufmann Brigitte
9031
p1
Gruppenleiter
15.04.1989
28559
p1
01.08.1988
28559
p2
Sachbearbeiter 01.02.1989
9031
p3
Sachbearbeiter 15.11.1988
29346
p1
Sachbearbeiter 01.04.1989
28559 Mozer
m_vorname
Sibille
abt_nr
a2
a1
mit_erweiter
m_nr
m_name
m_vorname
abt_nr
wohnort
25348 Keller
Hans
a3
Muenchen
10102 Huber
Petra
a3
Landshut
18316 Mueller
Gabriele
a1
Rosenheim
29346 Probst
Andreas
a2
Augsburg
9031 Meier
Rainer
a2
Augsburg
a2
Muenchen
a1
Ulm
2581 Kaufmann Brigitte
28559 Mozer
Sibille
3.1.2 Löschen von Objekten
Generelle Form der Anweisung:
DROP objektart obj_name
Z.B.:
DROP TABLE tab_name
Das Löschen einer Tabelle löscht natürlich auch alle Daten, aber auch zugehörige Indizes.
3.1.3 Abändern der Tabellenstruktur
Werden Tabellen im Rahmen der folgenden Manipulationen gelöscht, so werden auch alle dazugehörigen Objekte, wie Views oder Indices, gelöscht!
Ab OpenIngres 2.0 wird der SQL-Befehl Alter Table unterstützt. Diese Variante wird in den folgenden Fällen als erste Möglichkeit genannt.
3.1.3.1 Hinzufügen einer Spalte
Zu ändernde Tabelle sei test.
OpenIngres 2.0:
ALTER TABLE test ADD [COLUMN] NeueSpalte Spaltentyp
Skript zur Vorlesung Datenbanken VertiefungSeite 24
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Spaltentyp ist definiert wie bei Create Table. Die Klauseln not null with default, with null with default und not null not default sind jedoch nicht erlaubt.
Die Spalte wird immer an das Ende der Satzdefinition angefügt.
Alte Methode:
CREATE Table temp AS
SELECT test.*, VarChar('
FROM test;
') AS NeueSpalte
DROP test;
CREATE TABLE test AS
SELECT * FROM temp;
DROP temp;
Ist die neue Spalte in der Mitte der Spalten plaziert:
CREATE Table temp AS
SELECT Sp1, Sp2, VarChar('
') AS NeueSpalte,
Sp3, Sp4, Sp5
FROM test;
3.1.3.2 Löschen einer Spalte
OpenIngres 2.0:
ALTER TABLE test DROP [COLUMN] Spalte RESTRICT | CASCADE
Wenn Cascade spezifiziert wird, werden automatisch alle von der gelöschten
Spalte abhängigen Objekte (views, integrity constraints, grants, indexes) gelöscht.
Wenn Restrict spezifiziert wird und Abhängigkeiten existieren, wird die
Spalte nicht gelöscht.
Alte Methode:
Lasse eine Spalte bei SELECT aus:
CREATE Table temp AS
SELECT Sp1, Sp2, Sp4, Sp5
FROM test;
usw.
3.1.3.3 Ändern des Namens einer Spalte
CREATE Table temp AS
SELECT Sp1 AS Name, Sp2 AS Vorname, Sp4, Sp5
FROM test;
usw.
3.1.3.4 Ändern des Datentyps einer Spalte
Änderung der Spalte 4 von float4 zu float (8 Bytes):
CREATE Table temp AS
SELECT Sp1, Sp2, float8(Sp3) AS Sp3, Sp4
FROM test;
Skript zur Vorlesung Datenbanken VertiefungSeite 25
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
usw.
Vergrößerung einer VarChar-Spalte:
CREATE Table temp AS
SELECT Sp1, squeeze(pad(Sp2) + '
FROM test;
') AS Sp2, Sp3, Sp4
usw.
3.1.4 Vergabe von Rechten für Objekte
Der DBA muß seinen Gruppenmitgliedern Rechte für Tabellen etc. geben.
Das geschiegt mit dem grant Befehl:
grant priv {, priv} | all [privileges]
[excluding (columnname {, columnname})]
on [table] | procedure objname {, objname}
to userid {, userid} | public
[with grant option]
oder
...
to [user] | group | role | public [auth_id {, auth_id}]
...
Beispiel:
grant all on MyTable to group c100
Sonstige Privilegien:
• select
• update
• insert
• delete
Vergib DBA-Privileg für Datenbank:
grant db_admin on database dbv96_xxx to group c100
grant db_admin on database dbv96_xxx to i124
3.1.5 Integrität innerhalb einer Tabelle
Definition möglich mit Hilfe der folgenden Anweisung:
CREATE INTEGRITY ON tablename [corr_name] IS
search_condition
Beispiel:
CREATE INTEGRITY ON employee IS salary <= 150000;
Achtung bei NULLable-Feldern (a kann hier NULL sein:
CREATE TABLE test (a int, b int NOT NULL);
CREATE INTEGRITY ON test IS a > 10;
Fehler treten auf, da die Integritätsbedingung NULL nicht einschließt:
INSERT INTO test (b) VALUES (5);
Insert INTO test VALUES (NULL, 5);
Richtige Integritätsbedingung:
Skript zur Vorlesung Datenbanken VertiefungSeite 26
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
CREATE INTEGRITY ON test IS (a > 10) OR (a IS NULL);
3.1.6 Gruppen
Über Gruppen können Rechte für eine Liste von Ingres Benutzern (User IDs)
vergeben werden. Von User ingres erzeugt.
create group groupid {, groupid}
[with users = (userid {, userid})]
und
alter group groupid {, groupid}
add users (userid {, userid}) |
drop users (userid {, userid}) | all
sowie
drop group groupid {, groupid}
Skript zur Vorlesung Datenbanken VertiefungSeite 27
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
4 Windows4GL
4.1
Grundlagen
Windows4GL-Anwendung
• Graphische Benutzerschnittstelle (GUI) mit Application Editor als
„Screenpainter“ und Menü-Editor zum Erstellen
• Daten, z.B. von Tabellen können angezeigt und manipuliet werden (via
embedded SQL)
• Serie von „Fenstern“ (frames) mit Objekten
• Ereignisse (events) an Objekten können Aktionen auslösen
• Aktionen definiert in Windows4GL-Sprache, niedergelegt in Scripts (den
Objekten oder dem „Fenster“ zugeordnet)
• Jedes Event löst den Windows4GL-Code in einem Event Block aus
Komponenten einer Applikation:
• Frames mit Objekten und Scripts (User- und Ghost-Frames)
• Frame- und Field-Templates
• Prozeduren (Datenbank-, 4GL-, 3GL-)
• Include Scripts
• Globale Variablen
• Globale Konstanten
• Benutzer Klassen (User Classes)
Maustasten bei Benutzung des Editors:
• Linke Maustaste: Select
• Mittlere Maustaste: Details
• Rechte Maustaste: Properties
Starten durch
windows4gl datenbank
Beispiele in der Datenbank w4gldemo.
Erstes Fenster: Applikationen in der Datenbank
Nach Anwahl der Applikation: Component Catalog. Komponententypen s.o.
4.2
Frame-Editor
Frames sind die Bausteine der Applikation:
• Bilden Benutzerschnittstelle
• Zeigen Informationen
• Stellen Kontrollelemente zur Verfügung
• Anwender
− wechselt von Frame zu Frame
− gibt Daten ein oder läßt Daten anzeigen
− klickt Buttons oder wählt Menüpunkte aus
Skript zur Vorlesung Datenbanken VertiefungSeite 28
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Entwickler
− legt Layout und Aktionen fest
− legt Abläufe im Frame fest
− legt Ausführungsreihenfolge der Frames fest
− bestimmt, wie Daten in Frames dargestellt und zwischen Frames
übertragen werden
• Werden im Frame-Editor entwickelt und getestet
Es gibt zwei vordefinierte Frame Templates:
• Menu Frame
Default Menu Bar (File Menü mit Close Operation)
• Dialog Box Frame
Ohne Menu Bar, mit Ok und Cancel Buttons
Jedes Frame oder Frame Template hat einen zugeordneten Frame Style: Default visuelle Charakteristiken für jeden Feldtyp Õ Standardisierung des Erscheinungsbildes.
Ablauf der Anwendung = Folge von Frame Aufrufen. Möglichkeiten:
• Callframe
Ruft Frame als modales Fenster auf
• Openframe
Ruft Frame als nichtmodales Fenster auf. Benutzer kann auch mit dem
aufrufendem Frame wechselwirken.
• Gotoframe
Das aufrufende Frame wird geschlossen. Kontrolle geht an gerufenes
Frame über.
Beispiel aus dem video_list Frame der Videos Anwendung:
on click view_button =
begin
...
vlist[i].details_frame =
openframe video_detail(video_info=vlist[],
read_only = TRUE)
with windowtitle = vlist[].title;
...
end;
Innerhalb einer Form gibt es die folgenden Felder, die im Editor plaziert werden können:
• Entry Fields
Anzeige und Eingabe von Daten
• Button Fields
Auslösung von Aktionen durch Klick
• Toggle Fields
Durch Klick auf einen von zwei Zuständen setzbar (Ein/Aus)
Skript zur Vorlesung Datenbanken VertiefungSeite 29
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Enumerated Fields (Option-, List-)
Liste von Werten
• Analog Fields
Analoge Anzeige ganzzahliger Zahlenwerte (zwischen Min und Max)
• Image Fields
Bilder
• Shape Fields
Zur Dekoration (Hintergrund)
• Palette Fields
Gruppe von Buttons, jeder mit einem Image, jeder repräsentiert eine
wählbare Option
• Control Button Field
Bietet ein Menü möglicher Operationen (z.B. bei einem Table Field)
• Free Trim, Boxed Trim
Reiner Text
• Composite Fields
Enthalten beliebeige andere Felder
Aufruf aus dem Component Catalog.
Frame selektieren; mit Edit aus File-Menü oder mit Property-Taste.
Neues Frame mit File/Create.
4.3
Windows4GL am Beispiel
Es gibt drei Arten von Scripts:
• Frame Scripts
• Scripts für individuelle Felder oder Menüpunkte
• Include Scripts
• Scripts für Methoden von User Classes.
4.3.1 Das Frame „Hauptmenü“
Hier haben wir ein Frame Script. Frame Scripts könne aus drei Teilen bestehen:
• Optionaler initialize Block
Deklaration von Parametern, lokalen Variablen und lokalen Prozeduren
des Frames
• Event Blocks
Aufgerufen durch Aktionen des Benutzers oder des Programms (u.a.
auch Initialisierung des Frames)
• Optional der Code lokaler Proceduren
Ein Beispiel für ein Frame Script:
Skript zur Vorlesung Datenbanken VertiefungSeite 30
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
initialize =
begin
/* Fülle Table Field mit Auswahl */
/* und Frame Namen */
selection_table[1].frame_name = 'video_list';
selection_table[1].frame_desc = 'Video Liste';
selection_table[2].frame_name = 'cust_maint';
selection_table[2].frame_desc = 'Kunden-Verwaltung';
selection_table[3].frame_name = 'sales_chart';
selection_table[3].frame_desc = 'Verkaufsstatistik';
selection_table[4].frame_name = 'check_out';
selection_table[4].frame_desc = 'Ausleihe';
/* Zeige alle Einträge */
field(selection_table).NumVisibleRows =
selection_table.LastRow();
end;
on click go_button =
begin
callframe :selection_table[].frame_name;
end;
on click close_button,
on windowclose =
begin
exit;
end;
Schauen wir uns eines der Frames in der nächsten Stufe an: die Liste aller
Videos video_list. Daraus kann ein Eintrag ausgewählt werden. Ein DetailFrame kann aufgerufen werden. Mit diesem sind dann bestimmte Operationen möglich.
Skript zur Vorlesung Datenbanken VertiefungSeite 31
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
initialize (
user_name = varchar(32) not NULL,
dba_name = varchar(32) not NULL,
i
= integer,
video
= VIDEO_ROW, /* Klasse eines Video Eintrags */
close_details_frame = FrameExec,
delete_details_frame = FrameExec,
new_details_frame
= array of FrameExec
) =
begin
/* Wenn Benutzer DBA ist, mache Edit Button sichtbar */
select :user_name = dbmsinfo('username),
:dba_name = dbmsinfo('dba');
commit;
if user_name != dba_name then
field(view_edit_buttons.edit_button).CurBias =
FB_INVISIBLE;
field(create_button).CurBias = FB_INVISIBLE;
endif;
/* Lade Table Field mit allen Videos */
i = 1;
select :vlist[i].vid_no = vid_no,
:vlist[i].title = title,
...
:vlist[i].timestamp = timestamp
from v_video
order by title
begin
i = i + 1;
end;
commit;
end;
on click view_edit_buttons.view_button =
begin
if vlist[].details_frame is NULL then
vlist[].details_frame = openframe video_details (
video_info = vlist[], read_only = true)
with windowtitle = vlist[].title;
field(view_edit_buttons).CurBias) = FB_DIMMED;
end;
Skript zur Vorlesung Datenbanken VertiefungSeite 32
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
on childentry vlist =
begin
if vlist[].details_frame is NULL then
field(view_edit_buttons).CurBias = FB_CHANGEABLE;
else
field(view_edit_buttons).CurBias = FB_DIMMED;
end;
on userevent 'UpdateEntry' =
begin
video = VIDEO_ROW(CurFrame.MessageObject);
/* Welche Zeile im Table View enthält das Video? */
if find_video_row(video_list = vlist,
details_frame = video.details_frame,
row = byref(i)) = true then
if vlist[i].title != video.title then
/* Wenn Titel sich geändert hat, muß er neu */
/* einsortiert werden
*/
vlist.RemoveRow(rownumber=i);
/* Erzeuge leeren Eintrag an alphabetisch */
/* richtiger Stelle
*/
callproc insert_video_row(video_list = vlist,
title = video.title,
row = byref(i));
field(vlist).ActiveRow = i;
field(view_edit_buttons).CurBias = FB_DIMMED;
endif
vlist[i] = video;
endif
end;
4.4
Felder in einer Form
Man unterscheidet
• Active Fields
Wechselwirkung mit dem Benutzer möglich
• Inactive Fields
Nur Anzeige von Text, Daten, Bildern
• Composite Fields
Aus Einzelfeldern zusammengesetzt, gemeinsam manipulierbar
Gemeinsame Eigenschaften aller Felder:
• Field Property Sheets
Frame zur Manipulation der Eigenschaften eines Feldes
Skript zur Vorlesung Datenbanken VertiefungSeite 33
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Field Biases
Definiert, ob das Feld sichtbar ist und wie der Benutzer mit ihm wechselwirken kann.
Ein Frame kann in einem von 6 Framemodi sein:
• Update
Die zugehörigen Biases erlauben Read- und Update-Operationen
• Query
ditto
• Read
Die zugehörigen Biases erlauben Read-, aber keine UpdateOperationen
• User1, User2 oder User3
Benutzerdefinierte Frame Modi
In jedem Modus kann ein Objekt einen von 12 Biases annehmen. Diese
bestimmen die Sichtbarkeit des Objektes und die Art der möglichen Interaktion mit ihm (z.B. ob editierbar oder nicht):
Kategorie
Bias
Möglichkeiten
Interactive
Changeable
Select, Tab, Edit
Landable
Select, Tab
Visible
Sichtbar
Dimmed
Geschwächte Darstellung, keine Wechselwirkung möglich
Invisible
Unsichtbar, keine
Wechselwirkung möglich
Flexible
Select, Move, Resize
Resizable
Select, Resize
Moveable
Select, Move
Markable
Select
ClickPoint
Akzeptiert ClickPointEvent (Cursor Koord.)
DragBox
Eine Dragbox kann
durch das Feld gezeichnet werden
DragSegment
Ein Liniensegment
kann durch das Feld
gezeichnet werden
Passive
Select
Draw
• Variable Declared Feld
Normalerweise selektiert: OpenROAD deklariert automatisch eine mit
dem Feld verknüpfte Variable. Unter deren Namen ist der Wert des Feldes zugreifbar.
Skript zur Vorlesung Datenbanken VertiefungSeite 34
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
NIcht gewählt: Um dynamisch zur Laufzeit deklarierte Variablen zu benutzen.
• Mouse Move Text und Mouse Down Text
Texte, die bei der entsprechenden Aktion im Status Bar erscheinen
4.4.1 Entry Fields
Single-Line oder Multi-Line.
Ineinander überführbar (wenn Datentyp Varchar).
Ergebnis: eine Variable.
Kein Titel damit verknüpft!
Eigenschaften:
• Variable Name: Bezug bei Programmierung
• Data Type: Beschränkung auf Basisdatentypen möglich (default varchar)
− Varchar, Smallint, Integer, Float, Money, Date, StringObject
• Length (nur für varchar)
• Nullable: Setzbar zu NULL
• Mandatory
• Default value: Initialisierung des Feldes
• In Tab Sequence: Durch Tab erreichbar (wenn nicht: nur durch Maus
erreichbar)
• Script
Weitere Optionen: Single-Line oder Multi-Line, Password (ohne Echo),
Scrollbar (bei Multi-Line), Format für non-text Datentypen (Templates), Force
Case und Bias (s.u.).
4.4.2 Button
Eigenschaften:
• Variable Name
• Label text
• Previous Field (s.u.)
• Bias und Script
Effekt des Button-Click auf das vorherige Feld:
• Validated: Für das vorherige Feld wird ein SetValue Ereignis erzeugt
(Daten Validierung)
• Not Validated: Z.B. für Cancel Button
• Loses Focus: Input Focus geht auf neues feld über (Text Cursor, z.B. für
zwei Text Felder)
4.4.3 Toggle
Zwei Zustände.
Unterschiedliche Texte oder Bilder.
Zusätzlicher Indikator ist optional.
Skript zur Vorlesung Datenbanken VertiefungSeite 35
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Mehrere Toggles zu Stack zusammenfaßbar.
Eigenschaften:
• Variable Name (Typ Integer)
• Label Art (Text oder Image)
• Off/On Label Text bzw. Image
• Has Indicator
• Default
• Previous Field (s.o.)
• Bias und Script
4.4.4 Enumerated Fields
Radio-, List- oder Option-Field. Alle liefern nur einen Wert zurück! Alle haben praktisch dieselben Eigenschaften, nur unterschiedliche Erscheinungsformen:
Eigenschaften:
• Variable Name: Varchar (Text) oder Integer (Value)
• Nullable
• Value List
• Orientation
• Default
• Bias und Script
4.4.5 Analog Fields
Slider-, Bar- (für Bar-Charts) oder Scrollbar-Field. Ähnliche Eigenschaften.
Scrollbar im Prinzip wie Slider, Aussehen wie Standard-Scrollbars. Aktion
muß selbst programmiert werden („independent scrollbar“, z.B. horizontaler
Scrollbar für Table Field).
Eigenschaften:
• Variable Name: Integer
• Min und Max
• Default Wert
• Bias und Script
4.4.6 Image Fields
Vom Typ GIF, XBM oder Sun Raster.
Darstellbar nur durch 4GL Code.
Eigenschaften:
• Variable Name: BitmapObject
• Clipped
• Previous Field
• Bias und Script
Skript zur Vorlesung Datenbanken VertiefungSeite 36
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
4.4.7 Inactive Fields
Keine Interaktion mit dem Benutzer.
Shapes und Trim.
Shapes: Line, Rectangle, Ellipse
Trim: Image, Free text, Boxed text
Eigenschaften:
• Variable Name
• Bias
4.4.8 Composite Fields
Können gemeinsam manipuliert werden. Auch im Script unter einem Namen.
• Subform
Zusammenfassung mehrerer Felder in rechteckigen Grenzen
• Stack Field
Zusammenfassung mehrerer Felder, die vertikal oder horizontal ausgerichtet sind. Relative Position bleibt bestehen
• Matrix Field
Zusammenfassung mehrerer Felder in Matrix-Form. Relative Position
bleibt bestehen.
• Viewport
Subwindow für ein großes Feld mit horizontalem und vertikalen Scrollbar. Normalerweise für Images und Subforms.
• Flexible Form
Zusammenfassung mehrerer Felder in flexiblen Grenzen, d.h. die Flexible Form paßt sich bei Verschiebung einzelner ihrer Felder in der Größe
an. Anwendung nur während des Editierens!
• Table Field
Stellt Active Fields organisiert in Zeilen und Spalten dar. Jede Spalte ist
ein Stack identischer aktiver Felder.
Man kann die Anzahl der dargestellten Zeilen spezifizieren. Optionaler
vertikaler Scrollbar erlaubt das Scrollen.
Z.B. Tabelleninhalt in Zeilen und Spalten, vertikal oder horizontal.
4.5
Menu-Editor
Klassische Pull-Down Menüs. Zugang über Frame/Menu...
Menu Frames besitzen bereits ein Default Menü, Dialog Frames können
noch eines erhalten.
Komponenten:
• Button
Anklicken löst Aktion aus
• Toggle
Ein-/Ausschalter
• List
Auswahl aus Liste
• Slide-Off Menu
Menüpunkt zur Einleitung eines Submenüs
Skript zur Vorlesung Datenbanken VertiefungSeite 37
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Menu-Separator
Optische Abgrenzung
Button, Toggle und List sind mit dem Click-Event verknüpft.
Eigenschaften (teilweise kommen spezielle hinzu):
• Variable Name
• Script
• Label Text
• Speed Key (vordefinierte oder benutzerdefinierte Tasten, z.B. Funktionstasten), nur für Buttons und Toggles
• Focus Behaviour
• Bias
• Status Text
Biases für Menü-Elemente:
• Enabled
• Disabled
• Invisible
4.6
Scripts
4.6.1 Ereignisgesteuerte Programmierung
Auch „event-based“.
Ein Event ist ein Ereignis, das die Ausführung von Code anstoßen (triggern)
kann.
Der Code ist eine Sequenz von Windows4GL-Kommandos.
Syntax eines Event Blocks:
ON event1 [variablename1] {, ON event2 [variablename2]} =
[DECLARE
localvariablelist
[ENDDECLARE]]
BEGIN
statementlist
END;
Typische anwender-initiierte Events:
• Maus-Klick auf Button oder Feld
• Selektion eines Menüs
• Betreten, Verlassen eines Feldes
• Ändern von Feldinhalten
• Öffnen und Schließen eines Frames
Außerdem gibt es programmierte Events.
4.6.2 Scripts
Ein oder mehrere Eventblöcke.
Scripts können zugeordnet werden:
Skript zur Vorlesung Datenbanken VertiefungSeite 38
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Frame
• Field
• Menu Item
Frame-Script Syntax:
[INITIALIZE [([parameterlist])] =
[DECLARE
[localvariablelist]
[localprocedureforwardreference]
[ENDDECLARE]]
[BEGIN
statementlist
END[;]]
{eventblock[;]}
{localprocedure [;]}
Beispiel Frame Script:
/* Initialisiere das Frame */
INITIALIZE
(
id
= integer not NULL,
name = varchar(30) not NULL,
) =
DECLARE
i
= integer
ENDDECLARE
BEGIN
i = 0;
END;
ON CLICK clear_button =
BEGIN
id
= 0;
name = '';
END;
Field und Menu Item Script Syntax:
[INITIALIZE =
[DECLARE
[localvariablelist]
[localprocedureforwardreference]
[ENDDECLARE]]
Skript zur Vorlesung Datenbanken VertiefungSeite 39
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
[BEGIN
statementlist
END[;]]
{eventblock[;]}
{localprocedure [;]}
dabei ist eventblock
ON event1 {, ON event2} =
[DECLARE
localvariablelist
[ENDDECLARE]]
BEGIN
statementlist
END[;]
Beispiel Field Script für „close_button“:
/* Beende die Applikation */
ON CLICK =
BEGIN
return;
END;
Beispiel Menu Item Script für „menu.options_menu.help_menu“:
/* Zeigt Benutzerhilfe an */
ON CLICK =
BEGIN
message 'Geben Sie in beide Felder Werte ein ' +
'und wählen Sie eine Rechenoperation';
END;
Initialize Blöcke:
• In Frame Script vor denen der Field Scripts ausgeführt
• Kommandoausführung vor dem Maskenaufbau
• Enthält Deklaration der Parameterliste, die beim Aufruf übergeben werden kann
• Parameter könne wie lokale Variablen benutzt werden
Declare Block:
• Lokale Variablen
• Vorwärts-Referenzen für lokale Prozeduren (Prozedurköpfe)
User Class Script Syntax
[INITIALIZE =
DECLARE
localprocedureforwardreference
[ENDDECLARE]
Skript zur Vorlesung Datenbanken VertiefungSeite 40
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
{METHOD methodname [([parameterlist])] =
[DECLARE
localvariablelist
[ENDDECLARE]]
BEGIN
statementlist
END[;]}
{localprocedure [;]}
4.6.3 Windows4GL-Basissprachelemente
Verzweigung:
IF status = 1 THEN
4GLstatement1;
4GLstatement2;
ELSEIF status = 2 THEN
<4GL statements>
ELSEIF status = 3 THEN
IF value = 0 THEN
<4GL statements>
ELSE
<4GL statements>
ENDIF
ELSE
<4GL statements>
ENDIF;
FOR-Schleife:
FOR i = startexpr TO | DOWNTO endexpr DO
statement; {statement;}
ENDFOR;
Der Ablauf einer
ENDLOOP
CONTINUE
RESUME
RETURN
For-Loop kann mittels
/* Abschluß der Schleife */
/* Zum Beginn des nächsten Durchlaufs */
/* Beendet Schleife und Event Block */
/* Current Frame/Procedure/Method wird beendet */
geändert werden.
Skript zur Vorlesung Datenbanken VertiefungSeite 41
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
While-Schleife:
WHILE bed1 DO
<4GL statements>
WHILE bed2 DO
IF bed3 THEN
CONTINUE;
ENDIF;
<4GL statements>
IF bed4 THEN
ENDLOOP;
ENDIF;
ENDWHILE;
ENDWHILE;
Zuweisungen und Ausdrücke:
ergebnis = feld2 * (feld3 + feld4);
bereich = pi * r ** 2;
Kunde.Name = 'Müller';
Kundenliste[4].Adresse = 'Landstr. 8';
IF gehalt IS NULL THEN ... ;
IF persnr > 0 AND status != 2 THEN ... ;
IF name LIKE '%a' THEN ... ;
IF name NOT LIKE '%\[abd\]' ESCAPE '\' THEN ... ;
Modale Popup-Messagebox:
MESSAGE 'Geben Sie bitte in beide Felder Werte ein!';
MESSAGE 'Der Wert ist: ' + Varchar(feld1);
Modale Eingabeaufforderung:
antwort = PROMPT 'Geben Sie bitte Ihren Namen ein';
antwort muß dabei eine Varchar-Variable sein. Fenster hat Ok und Cancel
Buttons. Cancel verändert Variable nicht.
Rücksprung:
Aufruf von RETURN kehrt zum Vaterframe zurück, EXIT beendet die laufende Anwendung.
4.7
Objekte, Klassen, Variablen, Konstanten
Jede Komponente einer Windows4GL-Applikation ist ein Objekt. Stellen
Methoden zur Verfügung, haben Eigenschaften. System Classes sind vordefimniert.
User Classes sind benutzerdefinierbare Klassen mit Attributen und Methoden.
Skript zur Vorlesung Datenbanken VertiefungSeite 42
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
4.7.1 Variablen
Feld Objekte sind mit zwei Variablen verbunden:
• Die Datenvariable
− Speichert die angezeigten Daten
− Wird beim Anlegen des Feldes automatisch erzeugt
− Beispiel: EntryField mit Namen celsius
IF celsius > 100 THEN ...
• Die Referenzvariable
− Zeigt auf das Feld-Objekt
− Erlaubt die Manipulation der Objekteigenschaften (Größe, Farbe, ...)
− Zum Zugriff auf diese Referenzvariable muß man die field-Funktion
benutzen.
Beispiel:
FIELD(celsius).BgColor = CC_RED
− Schlüsselwort FIELD gib Zugang zu Attributen und Methoden des
Objektes
• Nur wenn die Referenzvariable auf ein Feld- oder Menu Item zeigt (die
mit einem Datenwert verknüpft sein können), ist zum Zugang zu den
Attributen und Methoden die field-Funktion notwendig, bei Referenzvariablen auf sonstige Objekte nicht!
• Beispiele:
CurFrame.TopForm.SetToDefault();
FIELD(ende_btn).SetAttribute(BgColor = CC_RED);
mitarbeiter_array.Clear();
letzte = mitarbeiter_array.LastRow();
FIELD(optfld).ValueList.ChoiceItems[i].EnumText = name;
4.7.2 System Classes
System Classes sind vordefinierte Windows4GL-Klassen mit eingebundenen
Attributen und Methoden.
Bilden eine Klassenhierarchie (Verallgemeinerung - Spezialisierung).
Enthalten alle Funktionalität, um eine GUI-basierte RDBMS-Anwendung zu
entwickeln.
Beispiel: Die System Class EntryField:
Typische Methoden und Attribute von Eingabefeldern:
Einige Attribute:
• ForceCase
Umwandlung groß/klein
• IsMultiLine
einzeilig/mehrzeilig
• TypeFace
Schrifttyp
• IsItalic
kursiv
Skript zur Vorlesung Datenbanken VertiefungSeite 43
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Einige Methoden:
• MarkAllText()
gesamten Text markieren
• UnmarkAllText()
Markierung aufheben
• MarkSubText()
Teil des Textes markieren
Vererbung aus der Klassenhierarchie:
Attribute der Klasse EntryField:
Attribut
Datentyp
Beschreibung
geerbt von
BgColor
integer
Hintergrundfarbe
FieldObject
ForceCase
smallint
Umwandlung groß/klein neu
IsMultiLine
smallint
einzeilig/mehrzeilig
neu
OutlineColor
integer
Farbe der Umrandung
ActiveField
Script
StringObject
4GL-Script des Feldes
FieldObject
4.7.3 User Classes
Definiert mit dem User Class Editor. Quasi RECORDs wie in Pascal.
Definition von Attributen (inkl. visibility), Methoden und des Scripts für alle
Methoden.
4.7.4 Variablen Typen
Einfache Variablen
• Enthalten nur einen Wert
• Jeder der Basistypen (integer, varchar, ...)
• Name referenziert Wert
• Beispiele:
person = 'Smith';
Einzelne Felder von Referenzvariablen (s.u.) können wieder einfache Variablen sein:
a.city
ar[i].city
• Deklaration:
name = datatype [WITH NULL | NOT NULL]
(WITH NULL ist default); z.B.:
i = integer;
Referenz Variablen
• Zeiger auf ein Objekt einer gegebenen Klasse
• Ohne Objekt hat die Referenz Variable den Wert NULL
• Zur Manipulation von Attributen und Aufruf von Methoden
• Zugriff auf Feld- und Menü-Objekte über FIELD-Funktion
Skript zur Vorlesung Datenbanken VertiefungSeite 44
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Als Parameter können auch Objekte (d.h. deren Ref. Var.) übergeben
werden
• Mehrere Referenz Variablen können auf dasselbe Objekt zeigen
• Beispiele für FIELD-Funktion (es sei ein Slider Field unter dem Namen
temperature in dem Frame definiert):
i = integer;
j = integer;
fld = sliderfield;
IF (temperature > 100) THEN
FIELD(temperature).BgColor = CC_RED;
i = FIELD(temperature).MinValue + 10;
j = FIELD(temperature).MaxValue;
ENDIF;
Dasselbe läßt sich auch folgendermaßen errreichen:
IF (temperature > 100) THEN
FIELD(temperature).SetAttribute(BgColor = CC_RED);
FIELD(temperature).GetAttribute
(MinValue=ByRef(i),
MaxValue=ByRef(j));
i = i + 10;
ENDIF;
Oder als dritte Möglichkeit:
IF (temperature > 100) THEN
fld = FIELD(temperature);
fld.BgColor = CC_RED;
i = fld.MinValue + 10;
j = fld.MaxValue;
ENDIF;
Dynamische Arrays
• Eine mit Namen versehene Menge von beliebig vielen Zeilen
• Alle Zeilen sind Referenz Variablen, die auf Objekte derselben Klasse
zeigen
• Automatische Anpassung der Anzahl beim Hinzufügen und Löschen
Man unterscheidet lokale und globale Variablen.
Lokale Variablen
• werden implizit beim Erstellen von Objekten angelegt
• können explizit im INITIALIZE-Block, im Kopf einer Prozedur oder im
DECLARE-Block angelegt werden
• sind dem Endanwender verborgen.
Globale Variablen
• werden im Global Variable Editor definiert
• sind global in der gesamten Applikation verfügbar
Skript zur Vorlesung Datenbanken VertiefungSeite 45
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• sind nicht mit Feldern oder Menü-Komponenten verbunden
• werden nicht dem Endanwender angezeigt
• können von jedem Objekttyp sein.
4.7.5 Konstanten
Man unterscheidet System und benutzerdefinierte Konstanten.
System Konstanten
• sind vordefiniert
• werden zum Setzen und Abfragen von Attributen benutzt
• Beispiele:
FALSE
TRUE
CC_BLUE
CC_LIGHT_GREEN
CC_RED
LW_THIN
LW_THICK
LW_VERYTHICK
FIELD(celsius).BgColor = CC_RED;
IF (FIELD(ef).IsItalic = TRUE) THEN ...
/* setzen */
/* prüfen */
Benutzerdefinierte Konstanten
• Definiert im Constant Editor
• Einer von drei Datentypen: integer, float oder varchar
• Nicht im Script änderbar
• Immer global
4.8
Vernüpfung mit Datenbank
Vier primäre Kommandos zum Zugriff auf eine Datenbank:
• SELECT,
• UPDATE,
• INSERT und
• DELETE.
Weitere unterstützende SQL-Befehle:
• COMMIT,
• ROLLBACK,
• INQUIRE_SQL,
Direkte reine SQL-Befehle über
• EXECUTE IMMEDIATE (stehen in VarChar-Variablen)
Cursor-Befehle
• OPEN
• FETCH
• CLOSE
Skript zur Vorlesung Datenbanken VertiefungSeite 46
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Verwendung von DataStream Objekten. Zwei Subklassen:
• SQLSelect
• QueryObject
4.8.1 SELECT-Befehl
Übergabe der selektierten Daten an einfache Variable, Referenz Variable oder
Array Variable.
Syntax:
[REPEATED] subselect
{UNION [ALL] subselect}
[ORDER BY orderspecification {, orderspecification}]
[BEGIN
statementlist
END;]
mit subselect als:
SELECT [ALL|DISTINCT]
resultexpression {, resultexpression}
FROM tablename [corrname] {, tablename [corrname]}
[WHERE searchcondition]
[GROUP BY columnname {, columnname}]
[HAVING searchcondition]
Zwei Arten des Selects:
• Singleton Select: Lies ein Tupel
• Select Loop: Lies mehrere Tupel in eine Ergebnis Tabelle
Das Schlüsselwort distinct verhindert, daß dasselbe Tupel mehrfach in der
Ergebnis Tabelle erscheint.
Das Schlüsselwort repeated sagt der Datenbank-Engine, daß sie den Query
Execution Plan aufbewahrt, so daß eine erneute, gleiche Abfrage in derselben
Applikation schneller bearbeitet werden kann.
resultexpression hat eine der beiden folgenden Formen:
:simple_variable = dbexpression
oder
dbexpression AS :simple_variable
4.8.1.1 Singleton Select
Nur eine Reihe wird selektiert.
(Variablen bekommen einen „:“ vorgestellt):
Skript zur Vorlesung Datenbanken VertiefungSeite 47
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON exit acctno_form.acctno =
BEGIN
/* Hole die Information des ausgewählten Kunden */
SELECT :checkout_form.cname = cname,
:checkout_form.acctno = acctno,
Kann in
:checkout_form.cphone = cphone
VarChar stehen
FROM customer
WHERE acctno = :acctno_form.acctno;
COMMIT;
END;
Gibt ein SELECT mehr als einen Wert zurück, so muß man entweder eine
Select Loop anwenden oder einen Cursor benutzen.
4.8.1.2 Select Loop
Annahme: Referenz Variable client mit den Feldern name, address und phone ist definiert. Zunächst wieder der Singleton Select:
name_var = 'Maier';
...
SELECT :client.name = cname,
:client.address = caddr,
:client.phone = cphone
FROM customer
WHERE cname = :name_var;
COMMIT;
Nehmen wir nun an, wir haben ein Array von client Referenz Variablen:
INITIALIZE =
DECLARE
client = ARRAY OF client_class,
i
= INTEGER
ENDDECLARE
ON CLICK selectButton =
BEGIN
client.Clear();
i = 1;
SELECT :client[i].name = cname,
:client[i].address = caddr,
:client[i].phone = cphone
FROM customer
BEGIN
i = i + 1;
END;
COMMIT;
END;
Dies ist eine Select Loop. Alle selektierten Reihen werden in das Array geschrieben.
Skript zur Vorlesung Datenbanken VertiefungSeite 48
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
4.8.2 Delete
Syntax:
[REPEATED] DELETE FROM tablename [corrname]
[WHERE searchcondition]
Beispiel:
DELETE FROM mitarbeiter
WHERE persnr = :persnr_efd;
4.8.3 Insert
Syntax:
[REPEATED] INSERT INTO tablename
[(columnname {, columnname})]
VALUES (expression {, expression}) | subselect
Beispiel:
INSERT INTO mitarbeiter (PersNr, Name)
VALUES (:KeyI + 1, :name_efd);
COMMIT;
Insert aus einem TableView:
i = CheckOutForm.CheckOut.FirstRow();
WHILE i <= CheckOutForm.CheckOut.LastRow() DO
...
IF CheckOutForm.CheckOut[i]._RowState = RS_NEW THEN
INSERT INTO v_checkout (acctno, vid_no, tape_no,
date_out, date_in, price)
VALUES ( :CheckOutForm.acctno,
:CheckOutForm.CheckOut[i].vid_no,
:CheckOutForm.CheckOut[i].tape_no,
:CheckOutForm.CheckOut[i].date_out,
:CheckOutForm.CheckOut[i].date_in,
:CheckOutForm.CheckOut[i].price);
ENDIF;
...
i = i + 1;
ENDWHILE;
COMMIT;
4.8.4 Update
Syntax:
[REPEATED] UPDATE tablename [corrname]
[FROM tablename [corrname] {, tablename [corrname]}]
SET columnname = dbexpr {, columnname = dbexpr}
[WHERE searchcondition]
Beispiel:
UPDATE mitarbeiter
SET gehalt = gehalt * :erhoeh_efd
WHERE name = :name_efd;
Skript zur Vorlesung Datenbanken VertiefungSeite 49
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Bedingung kann dynamisch sein:
bed = 'abteilung LIKE ''' + :abt_efd + '%''';
UPDATE mitarbeiter
SET gehalt = gehalt * :erhoeh_efd
WHERE :bed;
4.8.5 Cursor
Hierbei werden die Daten vom Backend zum Frontend in kleineren Paketen
transportiert: Sequentielle Verarbeitung.
Die Performance ist dabei schlechter als bei der Select Loop, die Syntax ist
komplexer, aber die Möglichkeiten der Gestaltung sind mfangreicher.
Beispiel:
/* Beispiel für ein CURSOR SELECT
Achtung: Keine vollständige Fehlerbehandlung! */
/* Deklaration einer Referenzvariable der Klasse
CursorObject
*/
INITIALIZE () =
DECLARE
tc = CursorObject
ENDDECLARE
ON CLICK auswahl =
BEGIN
IF tc.State != CS_CLOSED THEN
CLOSE tc;
ENDIF
/* Öffne Cursor
OPEN tc FOR SELECT
persnr,
name,
geburtstag,
chef,
gehalt,
kinder
FROM mitarbeiter
WHERE abteilung = :abteilung
AND
region
= :region
FOR UPDATE OF
name,
chef,
kinder;
CurFrame.SendUserEvent(eventname = 'Next');
END;
*/
Skript zur Vorlesung Datenbanken VertiefungSeite 50
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON CLICK weiter,
ON USEREVENT 'Next' =
BEGIN
FETCH tc INTO
:sf.persnr
:sf.name
:sf.gehalt
:sf.chef
:sf.kinder
:sf.geburtstag
=
=
=
=
=
=
persnr,
name,
gehalt,
chef,
kinder,
geburtstag;
IF tc.State = CS_NO_MORE_ROWS THEN
MESSAGE 'Keine weiteren Sätze';
ENDIF;
END;
Nach jedem Fetch werden die Attribute
• State
• RowCount (Zahl der insgesamt bisher fetched Rows)
des Cursor-Objektes sowie
• iirowcount (1 bei erfolgreichem Fetch, 0 sonst) und
• iierrrornumber (z.B. es stimmen die Variablen nicht mit den Spalten
überein)
gesetzt.
ON CLICK aendern =
BEGIN
UPDATE mitarbeiter
SET name
= :sf.name,
chef
= :sf.chef,
kinder = :sf.kinder
WHERE CURRENT OF tc;
CurFrame.SendUserEvent(eventname = 'Next');
END;
ON CLICK loeschen =
BEGIN
DELETE FROM mitarbeiter
WHERE CURRENT OF tc;
CurFrame.SendUserEvent(eventname = 'Next');
END;
Skript zur Vorlesung Datenbanken VertiefungSeite 51
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON CLICK speichern =
BEGIN
IF tc.State != CS_CLOSED THEN
CLOSE tc;
COMMIT;
ENDIF;
CurFrame.TopForm.SetToDefault();
END;
ON CLICK ende_btn =
BEGIN
IF tc.State = CS_OPEN THEN
CLOSE tc;
ROLLBACK WORK;
ENDIF;
RETURN;
END;
4.8.6 Zugriff mit Hilfe von DataStream Objekten
Flexible Möglichkeiten:
• Dynamische Änderungen zur Abfrage
• Vorwärts- und Rückwärts-Bewegung in der Ergebnismenge ist möglich.
Zwei Unterklassen:
• SQLSelect: nur Lesen; Benutzer schreibt Select-Befehl
• QueryObject: auch Add, Update, Delete; System generiert Select-Befehl
In allen Fällen sind die folgenden Schritte nötig:
• Erzeuge die SQLSelect oder QueryObject Instanz
• Spezifiziere die Abfrage (setze die Attribute des QueryObject entsprechend)
• Spezifiziere die Ziel-Felder oder -Variablen
• Rufe die Open-Methode auf, um die Daten abzufragen
• Rufe andere Methoden auf, um die Daten anzuzeigen
• Rufe die Close-Methode auf.
Es gibt 4 Beispiel-Frames in der Videos Anwendung (w4gldemo Datenbank):
• customer_browse und customer_browse2: SQLSelect Objekt
• customer_maintenance2: QueryObject Objekt, Änderungen erlaubt
• DynamicQuery: Dynamischer Aufbau eines QueryObject
4.8.6.1 Open Methode
Hierbei werden die Daten bereits selektiert. Es gibt 4 unterschiedliche Modes:
Skript zur Vorlesung Datenbanken VertiefungSeite 52
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Mode
QY_CACHE
QY_CURSOR
QY_DIRECT
QY_ARRAY
Beschreibung
Daten werden in einer Datei „gecached“. Rückwärtsnavigation
und wahlfreier Zugriff sind möglich
Verwendet einen DBMS Cursor
Analog zu einer Select Loop
Daten werden direkt in ein Array oder Table Field geladen
Im letzten Fall muß die Array-Klasse dieselben Attributnamen haben wie die
Spalten in der Datenbank-Anfrage.
4.8.6.2 SQLSelect
Zunächst muß das SQLSelect Objekt deklariert und instanziiert werden.
dann wird der Select-String aufgebaut.
INITIALIZE () =
DECLARE
ss
= SQLSelect;
/* Direkt instanziiert */
selectstring = VarChar(200) NOT NULL;
wClause
= VarChar(60) NOT NULL;
...
ENDDECLARE
BEGIN
selectstring = 'SELECT acctno, cphone, cname, caddr,'
+ ' ccity, cstate, czip, cdistrict,'
+ ' cstatus, cacctbal FROM v_customer';
Als nächstes muß für jedes selektierte Feld ein Ziel-Feld oder eine Zielvariable angegeben werden:
ss.Columns[1].Targets[1].Expression = 'customer.acctno';
ss.Columns[2].Targets[1].Expression = 'customer.cphone';
ss.Columns[3].Targets[1].Expression = 'customer.cname';
ss.Columns[4].Targets[1].Expression = 'customer.caddr';
...
FOR i = 1 TO ss.Columns.LastRow DO
ss.Columns[i].Targets[1].IsSelectTarget = TRUE;
ENDFOR;
END;
Das Attribut IsSelectTarget muß für jedes Ziel angegeben werden!
Wird ein Attribut der Datenbanktabelle in mehreren Zielen dargestellt, so
wird der Index von Targets inkrementiert.
Bisher ist die Where-Klausel noch nicht spezifiziert. Wir betrachten zwei
Fälle:
Abfrage nur eines bestimmten Satzes:
Skript zur Vorlesung Datenbanken VertiefungSeite 53
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
reply.Value = '';
status = CurFrame.ReplyPopup(
messagetext = 'Gib Kundennumer:',
reply = reply);
IF status != PU_OK THEN
RESUME;
ENDIF;
wclause = ' WHERE acctno = ' + reply.Value;
Abfrage aller Sätze mit bestimmten Status, sortiert nach Kundenname:
wclause = ' WHERE cstatus = 0 ORDER BY cname';
Nun muß die gesamte Query dem richtigen Attribut des SQLSelect Objektes
zugewiesen werden:
ss.Query.Value = selectstring + wclause;
Die Abfrage wird aber erst ausgeführt, wenn die Open Methode aufgerufen
wird.
Wird das SQLSelect Objekt im QY_ARRAY Modus geöffnet, so erscheinen die
Werte der Anfrage automatisch in den Ziel-Feldern/Variablen.
In allen anderen Modi stehen die beiden folgenden Methoden zur Verrügung:
• NextRow lädt die Daten Reihe für Reihe von der datenbank in den internen Puffer
• Load lädt die Daten aus dem internen Puffer in die Ziel-Felder/Variablen
Parameter der Open Methode:
Parameter
Typ
Default
Beschreibung
QueryMode
integer
keiner
QY_ARRAY, QY_CACHE, QY_CURCOR
oder QY_DIRECT
CheckCols
integer
FALSE
TRUE: Überprüfe Query auf existierende
Spalten
IsRepeated
integer
FALSE
TRUE: Erzeuge eine Repeat Query
MaxRows
integer
0
max. Anzahl zu füllender Array-Elemente
(nur in QY_ARRAY Mode)
Scope
Scope
akt. Scope Scope für die Auswertung der Ausdrücke
Attribut
in dem Columns array Targets Attribut
Alternativ kann das Scope-Attribut des SQLSelect Objektes auf das des aktuellen Frames gesetzt werden:
ss.Scope = CurFrame.Scope;
IF ss.Scope != CurFrame.Scope THEN
/* Ist es wirklich */
...
/* Fehler */
/* gesetzt?
*/
ENDIF;
Nun öffnen wir die Verbindung zur Datenbank mit der Open Methode (hier
wird Scope als Parameter übergeben):
Skript zur Vorlesung Datenbanken VertiefungSeite 54
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
status = ss.Open(querymode = QY_CACHE,
checkcols = TRUE,
Scope
= CurFrame.Scope);
IF status != ER_OK THEN
ROLLBACK;
MESSAGE 'SQLSelect error at open';
RESUME;
ENDIF;
COMMIT;
IF ss.ErrorNo != 0 AND ss.IsDBError = TRUE THEN
/* Es gab einen DB Fehler */
ROLLBACK;
MESSAGE 'DBMS Fehler beim Abfragen von ...';
RESUME;
ELSEIF ss.MaxRow = 0 THEN
/* Keine Reihen gefunden */
...
ELSEIF ss.MaxRow > 1 THEN
/* Enable Next-Button */
FIELD(NextBtn).CurBias = FB_CHANGEABLE;
ENDIF;
status = ss.NextRow();
/* Lade erste Reihe */
status = ss.Load();
/* Lades sie in Target */
END;
Navigieren innerhalb der Ergebnismenge:
ON CLICK NextBtn =
BEGIN
ss.NextRow();
ss.Load();
IF ss.CurRow = ss.MaxRow THEN
FIELD(NextBtn).CurBias = FB_DIMMED;
ENDIF;
FIELD(PrevBtn).CurBias = FB_CHANGEABLE;
END;
ON CLICK PrevBtn =
BEGIN
ss.PrevRow();
ss.Load();
IF ss.CurRow = 1 THEN
FIELD(PrevBtn).CurBias = FB_DIMMED;
ENDIF;
FIELD(NextBtn).CurBias = FB_CHANGEABLE;
END;
Wahlfreier Zugriff:
ss.FetchRow(rowindex = 4);
Erster Satz:
Skript zur Vorlesung Datenbanken VertiefungSeite 55
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ss.FetchRow(rowindex = 1);
Schließen des SQLSelect Objektes:
IF ss.State = QS_ACTIVE THEN
ss.Close();
ENDIF;
Man kann die Queries noch weiter parametrisieren: S. CA-OpenRoad Programming Guide!
4.8.6.3 QueryObject
Erlauben es auch, an den Inhalten der Datenbank Änderungen vorzunehmen.
Das QueryObject erlaubt es jedoch nicht, eine Query wie bei SQLSelect zu
formulieren (QueryObject.Query.Value ist readonly). Stattdessen muß man
eine anzahl von Attributen setzen, auf deren Basis dann das QueryObject
das Query Statement selbst erzeugt.
Die folgenden System Classes sind dabei involviert:
• DataStream
• QueryCol
• QueryParm
• SQLSelect
Weiterhin
• QueryObject
• QueryTable
Auch die Behandlung der Target Felder erfordert mehr Attribute:
Attribut
Default Beschreibung
Expression
keiner
Enthält Namen des Target-Feldes, z.B. „feld1“
oder „tbl[i].col1“
IsDBHandleField FALSE
Nur für String und Bitmap Objekte
IsInsertTarget
FALSE
TRUE, wenn Spalte Target für Insert ist
IsSelectTarget
FALSE
TRUE, wenn Spalte Target für Select ist
IsUpdateTarget
FALSE
TRUE, wenn Spalte Target für Update ist
IsDeleteWhere
FALSE
TRUE, wenn Spalte in Where-Klausel für Delete
verwendet wird
IsUpdateWhere
FALSE
TRUE, wenn Spalte in Where-Klausel für Update
verwendet wird
Der Gang der Handlung am Beispiel:
• Parameter zum Aufbau der SELECT Klausel setzen
BEGIN
qo.Tables[1].TableName = 'v_customer';
Skript zur Vorlesung Datenbanken VertiefungSeite 56
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
qo.Columns[1].ColumnName = 'acctno';
qo.Columns[2].ColumnName = 'cphone';
qo.Columns[3].ColumnName = 'cname';
qo.Columns[4].ColumnName = 'caddr';
qo.Columns[5].ColumnName = 'ccity';
qo.Columns[6].ColumnName = 'cstate';
qo.Columns[7].ColumnName = 'czip';
qo.Columns[8].ColumnName = 'cdistrict';
qo.Columns[9].ColumnName = 'cstatus';
qo.Columns[10].ColumnName = 'cacctbal';
FOR i = 1 TO qo.Columns.LastRow DO
qo.Columns[i].Targets[1].Expression = 'customer.'
+ qo.Columns[i].ColumnName;
qo.Columns[i].Targets[1].IsSelectTarget = TRUE;
qo.Columns[i].Targets[1].IsUpdateTarget = TRUE;
qo.Columns[i].FromTable = qo.Tables[1];
ENDFOR;
• Die Spalte acctno ist Primärschlüssel der Tabelle v_customer. Daher soll
sie nicht änderbar sein. Andererseits ist sie die zuständige Spalte für
die Where-Klausel bei Updates und Deletes.
qo.Columns[1].Targets[1].IsUpdateTarget = FALSE;
qo.Columns[1].Targets[1].IsUpdateWhere = TRUE;
qo.Columns[1].Targets[1].IsDeleteWhere = TRUE;
• Im nächsten Schritt wird die Order By Klausel gesetzt (analog geht man
für Group By vor):
qo.Columns[3].OrderBy = 1;
qo.Columns[3].AsName = 'cname';
END;
Die Navigation in dieser Anwendung erfolgt über ein Menü (man kann das
analog auch mit Buttons machen).
• Zunächst wird das QueryObject geschlossen, falls es noch offen war,
und die Menü-Einträge werden disabled:
IF qo.State = QS_ACTIVE THEN
qo.Close();
FIELD(menu.get_menu.next_account).CurBias = MB_DISABLED;
FIELD(menu.get_menu.prev_account).CurBias = MB_DISABLED;
ENDIF;
• Mit dem folgenden Stück Code wird (z.B. vor dem Schließen eines Frames) geprüft, ob an einem Feld eine Änderung vorgenommen wurde:
Skript zur Vorlesung Datenbanken VertiefungSeite 57
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
IF CurFrame.TopForm.HasdataChanged = TRUE THEN
status = CurFrame.ConfirmPopup(
messagetext = 'Ein Feld wurde verändert ...'
+ 'Trotzdem fortfahren?');
IF status != PU_OK THEN
RESUME;
/* Brich Aktion ab */
ENDIF;
ENDIF;
• Aktionen, wie Insert, Update, Delete werden durch Buttons gesteuert.
Bis die ersten Daten geladen wurden ist nur Insert möglich:
FIELD(insert_button).CurBias = FB_CHANGEABLE;
FIELD(update_button).CurBias = FB_DIMMED;
FIELD(delete_button).CurBias = FB_DIMMED;
• Weiterhin werden an dieser Stelle alle Felder gelöscht und der Cursor in
das feld cname des Matrix-Feldes customer positioniert:
CurFrame.TopForm.SetToDefault();
CurFrame.InputFocusField = FIELD(customer.cname);
• Als nächstes wird in Abhängigkeit der Benutzerwünsche die WhereKlausel aufgebaut. Es gibt 4 Wahlmöglichkeiten:
1. Ein neuer Account soll eingegeben werden: Keine Where-Klausel.
2. Benutzer gibt einen bestimmten existierenden Account ein.
3. Alle Accounts sollen selektiert werden: Leere Where-Klausel
4. Nur Accounts mit cstatus=0.
Der folgende Code leistet dies:
IF wahl = 1 THEN
RESUME;
/* Nur Insert möglich */
ELSEIF wahl = 2 THEN
reply.value ='';
status = CurFrame.ReplyPopup(
messagetext = 'Gib Account-Nr', reply = reply);
IF status != PU_OK THEN
RESUME;
/* negative Antwort */
ELSE
qo.RunTimeWhere.Value = 'acctno =' + reply.Value;
error_msg = 'Kein Kunde ' + reply.Value + ' gefunden!';
ENDIF;
ELSEIF wahl = 3 THEN
qo.RunTimeWhere.Value = ''; /* Alle Reihen */
error_msg = 'Es gibt keine Kunde';
ELSE
qo.RunTimeWhere.Value = 'cstatus = 0';
error_msg =
'Es gibt keine Kunde mit geschlossenen Accounts';
ENDIF;
Skript zur Vorlesung Datenbanken VertiefungSeite 58
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Nach all diesen Vorbereitungen kann es nun losgehen.
• Wir öffnen das QueryObject:
status = qo.Open(querymode = QY_CACHE);
IF status != ER_OK THEN
MESSAGE 'Fehler beim Öffnen des QueryObjects';
RESUME;
ENDIF;
COMMIT;
/* Multiuser-Fähigkeit ist gefährdet! */
• Anschließend werden jetzt mögliche Fehlerbedingungen des QueryObjects geprüft:
IF qo.ErrorNo != 0 AND qo.IsDBError = TRUE THEN
/* Ein DB Error ist aufgetreten */
MESSAGE 'DBMS Error ist aufgetreten';
ELSEIF qo.MaxRow = 0 THEN
MESSAGE error_msg;
/* Keine Reihen gefunden */
ELSE
/* Wenigstens 1 Reihe erhalten */
status = qo.NextRow();
status = qo.Load();
FIELD(insert_button).CurBias = FB_DIMMED;
FIELD(update_button).CurBias = FB_CHANGEABLE;
FIELD(delete_button).CurBias = FB_CHANGEABLE;
IF qo.MaxRow > 1 THEN
/* Mehr als 1 Reihe */
FIELD(menu.get_menu.next_account).CurBias = MB_ENABLED;
ENDIF;
ENDIF;
END;
Update mit QueryObjects
Event Block dafür:
ON CLICK update_button =
BEGIN
status = qo.DBUpdate(
ZeroRowsIsError = TRUE,
MaxRows = 1);
IF status != ER_OK OR qo.ErrorNo != 0 THEN /* Fehler */
ROLLBACK;
MESSAGE 'DBMS Fehler ' + VarChar(qo.ErrorNo);
ELSE
qo.CommitToCache();
COMMIT;
CurFrame.TopForm.HasDataChanged = FALSE;
ENDIF;
END;
Skript zur Vorlesung Datenbanken VertiefungSeite 59
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Delete mit QueryObjects
Der Event-Block dafür ist komplizierter, da man darauf reagieren muß, daß
im Cache nun eine Reihe weniger ist (evtl. gar keine mehr).
ON CLICK delete_button =
BEGIN
/* Lösche Kunden aus Datenbank */
status = qo.DBDelete(ZeroRowsIsError = TRUE,
MaxRows = 1);
IF status != ER_OK OR qo.ErrorNo != 0 THEN /* Fehler */
ROLLBACK;
MESSAGE 'DBMS Fehler ' + VarChar(qo.ErrorNo) +
' beim Löschen!';
ELSE
qo.CommitToCache();
/* Alles ok */
COMMIT;
CurFrame.TopForm.HasDataChanged = FALSE;
IF qo.MaxRow = 0 THEN
MESSAGE 'Keine Daten mehr anzuzeigen!';
CurFrame.TopForm.SetToDefault(); /* Lösche Felder */
FIELD(update_button).CurBias = FB_DIMMED;
FIELD(delete_button).CurBias = FB_ DIMMED;
ELSE
IF qo.CurRow > qo.MaxRow THEN
qo.PrevRow();
ENDIF
qo.Load();
IF qo.CurRow = qo.MaxRow THEN
FIELD(menu.get_menu.next_account).CurBias =
MB_DISABLED;
ENDIF;
IF qo.CurRow = 1 THEN
FIELD(menu.get_menu.prev_account).CurBias =
MB_DISABLED;
ENDIF;
ENDIF; /* Es gibt noch Daten */
ENDIF; /* Gelöscht o.k. */
END;
Insert mit QueryObjects
In dem Beispiel des customer_maintenance2 Frames wird nicht die DBInsert
Methode benutzt, da der Benutzer den Insert-Button auch dann drücken
kann, wenn noch kein QueryObject offen ist. Daher wird hier die normale
SQL Insert-Anweisung benutzt:
Skript zur Vorlesung Datenbanken VertiefungSeite 60
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON CLICK insert_button
BEGIN
IF CurFrame.TopForm.HasDataChanged = FALSE THEN
MESSAGE 'Bitte zuerst Daten eingeben!';
ELSE
/* Erzeuge neue eindeutige Kunden-Nummer */
:custome.acctno = CurFrame.DBSession.SequenceValue(
table_name = 'v_customer',
Column_name = 'acctno');
INSERT INTO v_customer (acctno, ..., cacctbal)
VALUES (:customer.acctno, ..., :customer.cacctbal);
IF CurFrame.DBSession.ErrorNumber != 0 THEN
error_msg = 'Kann keinen neuen Kunden eintragen! '
+ dbms_error_message();
ROLLBACK;
MESSAGE error_msg;
ELSE
COMMIT;
CurFrame.TopForm.SetToDefault();
ENDIF;
ENDIF;
END;
Hier wird die Prozedur dbms_error_message aufgerufen:
PROCEDURE dbms_error_message () =
BEGIN
IF CurFrame.DBSession.ErrorNumber != 0 THEN
RETURN 'Fehler Code ist ' +
VarChar(CurFrame.DBSession.ErrorNumber) + ' ';
ELSE
RETURN '';
ENDIF;
END;
Schließen eines QueryObjects
Hier kann zur Sicherheit abgefragt werden, ob auch alle in dem Frame geänderten Daten in die Datenbank geschrieben wurden:
Skript zur Vorlesung Datenbanken VertiefungSeite 61
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON CLICK close_button,
ON WINDOWCLOSE =
BEGIN
IF CurFrame.TopForm.HasDataChanged = TRUE THEN
status = CurFrame.ConfirmPopup(MESSAGETEXT =
'Alle geänderten Felder gehen verloren!');
ELSE
status = PU_OK;
ENDIF;
IF status = PU_OK THEN
qo.Close();
RETURN; /* Schließe das Frame */
ENDIF;
END;
4.8.7 Versionskontrolle eines Tabellentupels mit Hilfe einer Rule
Tabelle MeineTabelle habe die Spalten s1, ..., s12 und zusätzlich die Spalte
version vom Typ Integer. Dabei sei s1 der Primärschlüssel.
Die folgende Rule sorgt dafür, daß bei jedem Update der „normalen“ Tabellenspalten die Versionsnummer hochgezählt wird:
CREATE RULE MeineTabelleVersion
AFTER UPDATE(s1,...,s12) OF MeineTabelle
EXECUTE PROCEDURE AendereVersion(key = old.s1);
Die zugehörige Datenbank-Prozedur (muß vorher definiert worden sein; alle
Benutzer brauchen grant):
CREATE PROCEDURE AendereVersion
(key VarChar(10) NOT NULL) AS
BEGIN
UPDATE MeineTabelle
SET version = version + 1
WHERE s1 = :key;
END;
Der folgende Update basiert auf dem gemerkten Schlüssel und der gemerkten alten Versionsnummer:
UPDATE MeineTabelle
SET s2 = ...,
...
SET s12 = ...
WHERE (s1 = :oldKey) AND (version = :oldVersion);
COMMIT;
Hat sich die Versionsnummer geändert, wird das Tupel nicht mehr gefunden: iirowcount ist 0.
Skript zur Vorlesung Datenbanken VertiefungSeite 62
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
4.9
Arrays und Table Fields
Ein Table Field ermöglicht es, den Inhalt eines Arrays dem Benutzer darzustellen.
Es ist ein composite field, welches aus active fields arrangiert in Reihen und
Spalten besteht.
Jede Spalte stellt ein Attribut der mit dem Array assoziierten Klasse dar. Jede Zeile des Table Fields entspricht einer Zeile des Arrays. Ein Table Field
kann unter Umständen nur einen Subset der Attribute des Arrays darstellen, jedoch nicht mehr.
Table Fields erscheinen per Default als Tabelle und besitzen Tabellen- und
Spalten-Titel, Control Buttons und Scroll Bars.
Arrays können auch ohne zugehöriges Table Field benutzt werden.
4.9.1 Arrays
Ein Array ist eine mit Namen versehene Menge von Zeilen, wobei jede Zeile
eine Referenzvariable auf ein Objekt einer System oder User Klasse ist. Die
Attribute dieser Klasse stellen die Felder/Spalten des Arrays dar.
Deklaration:
INITIALIZE ( i_arr = ARRAY OF IntegerObject ) = ...
INITIALIZE () =
DECLARE
mit_arr = ARRAY OF mit_class
ENDDECLARE
...
Zugriff auf Arrays:
• Komplettes Objekt:
Arrayname
• Eine bestimmte Zeile:
Arrayname[Zeilennummer]
• Eine bestimmte Spalte:
Arrayname[*].Spaltenname
• Ein bestimmtes Attribut einer Zeile:
Arrayname[Zeilennummer].Spaltenname
• Anwenden von Methoden:
Arrayname.Methode()
Beispiele:
arr2
= arr1;
arr2
= arr1.Duplicate();
zeile
= arr[3];
arr[3].name = name_efd;
arr4[3].arr5[1].wert = 88;
arr.Clear();
Zeilenindex
• Zeilen werden beim Laden sequentiell ab 1 aufsteigend numeriert
(„Leerzeilen“ nicht möglich)
Skript zur Vorlesung Datenbanken VertiefungSeite 63
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Gelöschte Zeilen werden an den Anfang gestellt und ab 0 rückwärts
numeriert (0, -1, -2, ...)
Laden eines Arrays:
...
i = 1;
arr.Clear();
SELECT :arr[i].name
= name,
:arr[i].abteilung = abteilung
FROM mitarbeiter
BEGIN
i = i+1;
END;
...
Methoden für Arrays:
ArrayObject.Clear();
/* Löscht alle Zeilen */
integer = ArrayObject.InsertRow( ROWNUMBER=integer,
ROWOBJECT=Object );
integer = ArrayObject.RemoveRow( ROWNUMBER=integer );
integer = ArrayObject.SetRowDeleted( ROWNUMBER=integer );
integer = ArrayObject.Sort( attributname = order, ... );
Rückgabewerte der drei mittleren Methoden:
ER_OK, ER_OUTOFRANGE, ER_ROWNOTFOUND
Werte für order:
AS_ASC, AS_DESC
Attribute von Arrays:
integer = ArrayObject.FirstRow;
integer = ArrayObject.LastRow;
integer = ArrayObject.AllRows;
/* Anzahl Zeilen */
integer = ArrayObject._RowState;
Mögliche Werte von _RowState:
RS_CHANGED, RS_DELETED, RS_NEW,
RS_UNCHANGED, RS_UNDEFINED
Suche in einem Array:
i = arr.FirstRow;
WHILE ( i <= arr.LastRow ) DO
IF arr[i].Spalte = Suchbedingung THEN
...
ENDIF
i = i + 1;
ENDWHILE;
Es gibt auch eine Find Methode!
Skript zur Vorlesung Datenbanken VertiefungSeite 64
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
4.9.2 Table Fields
Ein TableField besteht aus ActiveFields, die in Zeilen und Spalten angeordnet sind.
• Jede Spalte ist ein Stack identischer ActiveFields
• Jede Zeile hat dieselbe Struktur, ähnlich einer Reihe aus einer Datenbanktabelle
ActiveFields können von jedem Typ (einer Spezialisierungs-Klasse) sein, meistens sind es EntryFields. Andere Möglichkeit wären ToggleFields.
TableField ist eine Unterklasse von CompositeField.
Die Zahl der sichtbaren Zeilen ist wählbar und zur Laufzeit änderbar.
Anzeige über Scrollbars.
Es gibt vertikale (Default) und horizontale TableFields
Ein TabelField wird immer automatisch mit einem dynamischen Array verknüpft, über das auf die Daten im TableField zugegriffen werden kann.
Objekte eines TableFields: TableField, ColumnField (eines für jede Spalte),
CellAttribute (für jede Zelle, normalerweise abgeschaltet)
TableField-Komponenten:
Individual
Column Titel
Table Field Background
Table Titel
Table
Header
Control Button
Prototype
Field
Individual
Cell
Table Body
Column Field
Beispiele für den Zugriff auf die Elemente des Table Field:
• Table Titel (VarChar(256))
FIELD(tablefield).Title = title_string;
• Table Header (StackField)
Scrollbar
Skript zur Vorlesung Datenbanken VertiefungSeite 65
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
FIELD(tablefield).TableHeader.attribute = value;
• Individuelle Zelle
FIELD(tablefield[n].columnname).attribute = value;
Beispiele für Manipulation von Table Field Komponenten (Name des Table
Fields sei tab):
FIELD(tab).TableHeader.BgPattern = FP_SHADE;
FIELD(tab).TableHeader.OutlineStyle = LS_DASH;
FIELD(tab).Title='Mitarbeiter';
FIELD(tab).TitleTrim.BgColor = CC_PALE_BLUE;
FIELD(tab[*].gehalt).Title='Rente';
FIELD(tab[*].gehalt).TitleTrim.BgColor = CC_RED
FIELD(tab).
ControlButton =
NULL;
FIELD(tab).TableBody.OutLineWidth = LW_THIN;
FIELD(tab).NumVisibleRows = 8;
FIELD(tab[*].gehalt).bgpattern = FP_SHADE;
EntryField(FIELD(tab[*].gehalt).ProtoField).IsBold = TRUE;
/* Alle Zeilen dieser Spalte ändern */
FIELD(tab[5].name).BgColor = CC_RED;
/* CellAttributes must be On */
FIELD(tab).HasScrollBars = FALSE;
Zugriff auf die Inhalte des Table Fields:
• Alle Funktionalitäten von dynamischen Arrays
• Quasi ein Fenster über dem dynamischen Array
• Dieselbe Syntax
Skript zur Vorlesung Datenbanken VertiefungSeite 66
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Zusätzliche Möglichkeiten:
− Leere eckige Klammern: aktuelle Zeile
sf = tab[];
− Attribute CurRow, ActiveRow und TopRow erlauben Zusammenhang zwischen Table Field und Array.
Hole Array-Index der aktuellen Zeile:
i = FIELD(tab).CurRow;
/* wird beim Verlassen des TableFields NICHT geändert */
i = FIELD(tab).ActiveRow;
/* wird beim Verlassen des TableFields auf 0 gesetzt */
Hole Index der ersten im Table Field sichtbaren Zeile:
i = FIELD(tab).TopRow;
/* Attribut ist jetzt auch schreibbar! */
− Über das Attribut _RowState kann der Zustand einer Zeile ermittelt
werden:
Symbolische Konstanten dafür:
RS_UNDEFINED
RS_NEW
RS_UNCHAGED
RS_CHANGED
RS_DELETED
Änderungen des _RowState durch Wertzuweisung zum Attribut möglich, normalerweise aber durch Benutzereingaben oder die Methode
SetRowDeleted().
Unsichtbare Spalten im Table Field
Wenn die Array-Klasse mehr Elemente hat, als das Table Field Spalten besitzt, so sind die überzähligen Spalten des Arrays effektiv verborgen.
Weitere Beispiele:
Selektiere eine bestimmte Zeile:
ON CLICK menu_button.ChangeRow =
BEGIN
resp = prompt 'Enter the number of row you want to see';
status = custtable.SetInputFocus(row=int4(resp));
...
BEGIN
Prüfe Frame Modus und ändere das Operations Menu
Skript zur Vorlesung Datenbanken VertiefungSeite 67
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
INITIALIZE (
...
) =
BEGIN
IF CurFrame.CurMode = FM_READ THEN
FIELD(custtable).CurOps = OP_NONE;
ELSEIF CurFrame.CurMode = FM_UPDATE THEN
FIELD(custtable).CurOps = OP_APPEND;
ENDIF;
...
END;
Formatierung einer mehrzeiligen Überschrift
FIELD(movie[*].director).title = 'Director''s' + HC_NEWLINE
+ 'Name';
Eine bestimmte Spalte unsichtbar machen
SELECT :user_name = DBMSInfo('username'),
:dba_name = DBMSInfo('dba');
COMMIT;
IF user_name != dba_name THEN
FIELD(custtable[*].acctbal).CurBias = FB_INVISIBLE;
Zwei Varianten für Einlesen in ein TableField und Updates aus einem
TableField heraus:
Prinzipiell kann diese Vorgehensweise hier nicht generell
empfohlen werden. Das gezeigte Beispiel verwendet pessimistische Concurrency Control und ist deadlockgefährdet!
Version mit User-Event:
/*
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
*/
Application:
Frame:
tablefield_update
tableupdate
This example displays two columns from the 'part' table of the
database, and then allows the user to browse and edit the
data. When the user selects the 'load' button, the data is
loaded into the table field, and a new transaction is begun.
When the user selects the 'update' button, the changes
are applied to the 'part' table.
This uses a UserClass called 'part_object' that contains three
attributes:
partno
- the part number.
short_desc - the short description.
partno_save - the part number saved on the side (to use for
updating). This is not displayed.
This allows us to keep a 'hidden' column in the tablefield
that will not be displayed, but contains the partno key, unchanged
by the user.
INITIALIZE
(
Skript zur Vorlesung Datenbanken VertiefungSeite 68
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
i = integer
/* Temporary counter */
) =
BEGIN
CurFrame.SendUserEvent (eventname = 'load_data');
END;
ON CLICK load_button,
ON USEREVENT 'load_data' =
BEGIN
COMMIT;
/* Start a new transaction */;
parttable.Clear();
/* Clear out array */
i = 1;
SELECT :parttable[i].partno = partno,
:parttable[i].partno_save = partno,
:parttable[i].short_desc = short_desc
FROM
part
BEGIN
i = i + 1;
END;
END;
ON CLICK update_button =
BEGIN
i = parttable.FirstRow();
/* No error checking is done for simplicity of example */
WHILE i <= parttable.LastRow() DO
IF parttable[i]._rowstate = RS_DELETED THEN
REPEATED DELETE FROM part
WHERE partno = :parttable[i].partno;
ELSEIF parttable[i]._rowstate = RS_NEW THEN
REPEATED INSERT INTO part
(partno, short_desc)
VALUES
(:parttable[i].partno, :parttable[i].short_desc);
ELSEIF parttable[i]._rowstate = RS_CHANGED THEN
/* Does not allow direct update of key value */
REPEATED UPDATE part
SET short_desc = :parttable[i].short_desc,
partno = :parttable[i].partno
WHERE partno = :parttable[i].partno_save
ENDIF;
i = i + 1;
ENDWHILE;
COMMIT;
END;
Version mit lokaler Prozedur:
/*
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
**
*/
Application:
Frame:
tablefield_update
tableupdate
This example displays two columns from the 'part' table of the
database, and then allows the user to browse and edit the
data. When the user selects the 'load' button, the data is
loaded into the table field, and a new transaction is begun.
When the user selects the 'update' button, the changes
are applied to the 'part' table.
This uses a UserClass called 'part_object' that contains three
attributes:
partno
- the part number.
short_desc - the short description.
partno_save - the part number saved on the side (to use for
updating). This is not displayed.
This allows us to keep a 'hidden' column in the tablefield
that will not be displayed, but contains the partno key, unchanged
by the user.
INITIALIZE
Skript zur Vorlesung Datenbanken VertiefungSeite 69
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
(
) =
DECLARE
i = integer not null;
load_data = procedure;
ENDDECLARE
BEGIN
callproc load_data;
END;
/* Temporary counter */
/* Vorwärts Deköaration */
ON CLICK load_button =
BEGIN
callproc load_data;
END;
ON CLICK update_button =
BEGIN
/* No error checking is done for simplicity of example */
FOR i = parttable.FirstRow TO parttable.LastRow DO
IF parttable[i]._rowstate = RS_DELETED THEN
REPEATED DELETE FROM part
WHERE partno = :parttable[i].partno;
ELSEIF parttable[i]._rowstate = RS_NEW THEN
REPEATED INSERT INTO part
(partno, short_desc)
VALUES
(:parttable[i].partno, :parttable[i].short_desc);
ELSEIF parttable[i]._rowstate = RS_CHANGED THEN
/* Does not allow direct update of key value */
REPEATED UPDATE part
SET short_desc = :parttable[i].short_desc,
partno
= :parttable[i].partno
WHERE partno = :parttable[i].partno_save
ENDIF;
ENDFOR;
COMMIT;
END;
PROCEDURE load_data() =
DECLARE
i = integer
ENDDECLARE
BEGIN
COMMIT;
/* Start a new transaction */;
parttable.Clear();
/* Clear out array */
i = 1;
SELECT :parttable[i].partno = partno,
:parttable[i].partno_save = partno,
:parttable[i].short_desc = short_desc
FROM
part
BEGIN
i = i + 1;
END;
END;
4.10 Frameaufrufe und Kommunikationstechniken
Planung der Anwendung. Die grundsätzliche Struktur wird davon bestimmt,
in welcher Reihenfolge und in welchem Modus Frames nacheinander geöffnet werden (z.B. immer nur ein aktives Frame oder mehrere aktive Frames).
Z.B.: Ein Hauptmenü-Frame, aus dem dann die Unterfunktionen aufgerufen
werden. Auf Menüleiste kann ganz verzichtet werden. Beispiel: „Videos
Application“ aus w4gldemo.
4.10.1 Auswahl über ein Table Field
Ausgangpunkt ist Dialogframe mit Open und Quit Buttons: In Tablefield
steht Auswahlliste: Markieren, dann Open drücken.
Skript zur Vorlesung Datenbanken VertiefungSeite 70
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Frame Script:
INITIALIZE =
BEGIN
/* Fuelle Table Field mit Frame Namen und Auswahl Text */
SelTable[1].FrameName = 'video_list';
SelTable[1].Descr
= 'Video List';
SelTable[2].FrameName = 'customer_maintenance';
SelTable[2].Descr
= 'Customer Maintenance';
SelTable[3].FrameName = 'sales_barchart';
SelTable[3].Descr
= 'Sales Charts';
SelTable[4].FrameName = 'check_out';
SelTable[4].Descr
= 'Check Out/In Videos';
/* Passe Groesse der Tabelle an
FIELD(SelTable).NumVisibleRows = SelTable.LastRow;
END;
*/
ON CLICK go_button =
BEGIN
/* Name des zu rufenden Frames ist in der verborgenen
Spalte
*/
callframe :SelTable[].FrameName;
END;
ON CLICK close_button,
ON windowclose =
BEGIN
exit;
END;
Bezeichnet aktuell
markierte Zeile
4.10.2 Kommunikaton zwischen Frames
Mehrere Möglichkeiten:
• Parameterübergabe
• Globale Variable
• Globale Konstanten
• User Events (lösen Aktionen in einem anderen Frame aus: SendUserEvent-Methode)
• Datenbank Events (Kommunikation zwischen zwei Anwendungen, die
über dieselbe Datenbank miteinander verbunden sind; erstellt über
SQL-Skript, ausgelöst durch Datenbank)
4.10.3 Scope
• Frames sind zugreifbar von allen anderen Frames der Anwendung.
Skript zur Vorlesung Datenbanken VertiefungSeite 71
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Datenbankprozeduren müssen registriert werden, um direct vom 4GLCode aufgerufen werden zu können.
• 4GL-Prozeduren und Variable, die in der declare-Sektion eines 4GLScript definiert sind, sind nur lokal zu diesem Script sichtbar.
Sind sie im Frame-Script definiert, so gelten sie auch für alle EventBlöcke von Feldern dieses Frames.
• Lokale Prozeduren werden am Ende eines Scripts – hinter allen EventBlöcken – implementiert.
• Field-Variable sind lokal im Frame sichtbar
• Variablen, die innerhalb der Klammern eines initialize-Blocks definiert
sind, sind außerhalb des Frames als Parameter sichtbar.
4.10.4 Frameaufrufe
Bei jedem Frame-Aufruf wird eine Instanz der Klasse FrameExec erzeugt.
Enthält Informationen über den augenblicklichen Zustand des laufenden
Frames (Information über Felder: InputFocusField, CurMode des Frames, das
letzte event: Messagexxx). Weiterhin ermöglicht es die Kommunikation zwischen Frames (SendUserEvent-Methode, aber auch Beep(), PopUp-Fenster ).
Referenzierung über System-Variable CurFrame.
Verschiedene Möglichkeiten des Aufrufs:
• openframe
Öffnet neues Frame, voriges ist weiterhin aktivierbar.
• callframe
Öffnet neues, modales Frame, andere Frames sind nicht aktivierbar
(blockiert, Maus erscheint als Uhr)
• gotoframe
Schließt voriges Frame, geht zu dem neuen Frame, kein Zurück
Achtung, wenn mehrere aktive Frames offen sind!
Normalerweise hat die Anwendung nur eine Datenbankverbindung (Session). Jedes Commit oder Rollback in einem der Frames wirkt sich auf die offene Transaktion
aus!
4.10.4.1 openframe
Aufruf:
FrameExecVar = openframe framename ( [parameterlist] )
[ with [parentframe=FrameExecVar | NULL ] |
[optionlist] ]
mit parameterlist:
parameter_name=expression {, parameter_name=expression}
parameter_name ist Feldname oder lokale Variable des neuen Frames. expression kann Felder, Konstanten oder Variablen des rufenden Frames enthalten.
mit optionlist:
option=value {, option=value}
Skript zur Vorlesung Datenbanken VertiefungSeite 72
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Das aufrufende Frame bleibt aktiv während das aufgerufene Frame läuft.
Um eine Kommunikation zu ermöglichen, erhält das aufrufende Frame eine
Referenz-Variable auf das aufgerufenen Frame als Funktionswert zurück
(Typ FrameExec).
Für dieses
Detail noch
kein DetailFrame offen
Beispiel:
ON CLICK view_edit_buttons.edit_button =
BEGIN
IF vlist[].details_frame IS NULL THEN
Hier ist
Referenz auf
vlist[].details_frame = openframe video_detail
neues Frame
(video_info = vlist[], read_only = FALSE)
gespeichert;
with windowtitle = vlist[].title;
Datentyp
FrameExec
FIELD(view_edit_buttons).CurBias = FB_DIMMED;
ENDIF;
END;
Frameparameter
Frameattribute
der
Framedefinitio
n
Anderes Beispiel:
graphic_frame = openframe video_graphic
(vid_graphic_bitmap = video.vid_graphic_object)
with window_title = video.title,
windowxleft = CurFrame.WindowWidth,
windowytop = 0;
Später kann diese Referenz benutzt werden:
IF menu.view_menu.show_graphic = FALSE THEN
graphic_frame.Terminate();
graphic_frame = NULL;
ENDIF;
4.10.4.2 callframe
Variable = callframe framename [ (parameterlist) ]
[with optionlist]
Bis auf Rückgabewert alles wie oben. Rückgabewert durch
Aufruf:
return
expression
im aufgerufenen Frame (Datentypen müssen übereinstimmen).
Übergebene Parameter können auch by reference sein (nur bei callframe!):
callframe myframe (number = ByRef(int_var),
check_rec = ByRef(ref_var),
movies = ByRef(array_var));
Wird eine Referenzvariable by reference übergeben, so kann diesem Pointer
ein anderes Objekt zugewiesen werden!
Skript zur Vorlesung Datenbanken VertiefungSeite 73
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
4.10.4.3 gotoframe
gotoframe framename [ (parameterlist) ]
[with optionlist]
Das rufende Frame wird geschlossen! Daher ohne Rückgabewert!
Das aufgerufene Frame ersetzt das aufrufende!
Daher ist Rücksprung in das Elternframe des aufrufendem Frames möglich!
Sogar unter Ausnutzung des Return-Parameters, wenn Datentypen übereinstimmen.
Keine ByRef-Funktion!
Aufruf:
4.10.4.4 FrameExec Objekt
CurFrame gib Zugriff auf das Frame-Objekt.
Ändern der Größe des Fensters, der Hintergrundfarbe, des Feldes, welches
den Input Fokus besitzt:
CurFrame.InputFocusField = FIELD(customer.cname);
4.10.4.5 Pop-up Windows
Die Arten:
Pop-up Fenster Typ
Beschreibung
Information Pop-up
Dialog-Box mit einer Message und OK-Button
Confirm Pop-up
Zusätzlich ein Cancel-Button
Reply Pop-up
Message, Prompt Line (zur Eingabe), OK-Button
File Pop-up
Message, File Selection Area, Cancel- und OK-Button,
Reply als Ergebnis
Information- und Reply-Pop-ups auch mit message bzw. prompt. Sonst:
CurFrame.InfoPopUp
(messagetext=varchar(256) [,
messagetype=integer]);
message varchar(256);
CurFrame.ConfirmPopUp(messagetext=varchar(256));
CurFrame.ReplyPopUp
(messagetext=varchar(256)
reply=StringObject);
reply = prompt varchar(256);
CurFrame.FilePopUp
(messagetext=varchar(256),
reply=StringObject);
Alle liefern einen Integer-Wert als Ergebnis:
PU_OK oder PU_CANCEL
Dasselbe geht auch aus einer 4GL-Procedure:
CurProcedure.InfoPopUp(parms);
Skript zur Vorlesung Datenbanken VertiefungSeite 74
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Beispiel:
ON CLICK delete_button =
BEGIN
status = CurFrame.ConfirmPopup(messagetext =
'Achtung: Sie löschen jetzt!');
IF status != PU_OK THEN
resume
ELSE
...
ENDIF;
END;
ReplyPopup und FilePopup haben eine Reply-Parameter (file_name ist ein
StringObject):
file_name.Value = '';
status = CurFrame.FilePopup(messagetext =
'Gib Name des Files:', reply = file_name);
IF status = PU_OK THEN ...
4.10.4.6 Schließen eines Frames:
return
4.10.5 Framekommunikation mit User Events
4.10.5.1 Events empfangen
Syntax:
ON USEREVENT ['Eventname'] =
BEGIN
kommandoliste;
END;
Ohne Eventname: Für alle User Events, für die das Frame keinen Usereventblock hat.
Nur im Frame Script!
Beispiele:
ON USEREVENT 'uhrzeit' =
BEGIN
uhrzeit_efd = DATE('NOW');
END;
ON USEREVENT =
BEGIN
MESSAGE 'Event ohne Block erhalten!!!';
END;
4.10.5.2 Events versenden
Methode SendUserEvent der Klasse FrameExec. Sendet an das durch die
FrameExec-Variable bezeichnete Frame das Event.
Skript zur Vorlesung Datenbanken VertiefungSeite 75
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Syntax:
FrameExecVar.SendUserEvent(
EVENTNAME = varchar(256)
[, MESSAGEOBJECT = Object
[, MESSAGEINTEGER = Integer
[, MESSAGEFLOAT
= Float
[, MESSAGEVARCHAR = VarChar
[, DELAY
= Float
[, FOCUSBEHAVIOR = Integer
]
]
]
]
]
]);
Messageparameter dienen der Datenübertragung. Können in dem zugehörigen empfangenden Eventblock unter den oben genannten Namen empfangen
werden.
FOCUSBEHAVIOR triggert im empfangenden Frame ein SetValue-Event für
das aktive Feld (FT_SETVALUE) evtl. mit zusätzlichem Exit-Event
(FT_TAKEFOCUS). Default ist, daß nichts geschieht (FT_NOSETVALUE). Das
geschieht, bevor der aktuelle Event-Block bearbeitet wird.
DELAY läßt das Event erst nach der angegebenen Zahl Sekunden in der
Event-Queue erscheinen.
Beispiel:
INITIALIZE () =
BEGIN
CurFrame.SendUserEvent(EVENTNAME = 'uhrzeit');
END;
ON USEREVENT 'uhrzeit' =
BEGIN
uhrzeit_efd = DATE('NOW');
CurFrame.SendUserEvent( EVENTNAME = 'uhrzeit',
DELAY = 60);
END;
Beispiel für Datenübertragung:
/* Absenderframe */
FE_ptr.SendUserEvent( EVENTNAME
MESSAGEOBJECT
MESSAGEINTEGER
= 'update_zeile',
= arr[i],
= i);
/* Empfängerframe */
ON USEREVENT 'update_zeile' =
BEGIN
zeile = mit_class(CurFrame.MessageObject); /* Type Cast*/
i
= CurFrame.MessageInteger;
...
END;
Anderes Beispiel:
Ein Child-Frame, welches von dem Parent-Frame geöffnet wurde, soll dem
Parent-Frame eine Information zurück übermitteln.
Skript zur Vorlesung Datenbanken VertiefungSeite 76
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Vom main_frame werde ein detail_frame geöffnet für eine bestimmte Reihe
des Table Field testtable (in main_frame).
Schicke Referenz
/* Script for Main_Frame */
auf main_frame
ON CLICK open_detail =
mit
BEGIN
OPENFRAME detail_frame (
parentframe = CurFrame,
rownumber = FIELD(testtable).CurRow);
Zeilennummer
testtable[].IsOpen = TRUE;
wird später
END;
gebraucht
...
ON USEREVENT 'Detail Close' =
BEGIN
testtable[CurFrame.MessageInteger].IsOpen = FALSE;
END;
/* Script for Detail Frame */
INITIALIZE(
parentframe = FrameExec,
rownumber
= integer) =
BEGIN
/* Load detail information */
...
END;
...
ON CLICK close_button =
BEGIN
parentFrame.SendUserEvent (
eventname = 'Detail Close',
messageinteger = rownumber);
RETURN;
END;
Beispiel für SetValue Event in Verbindung mit Lookup:
Lokale Variablen, werden bei
Aufruf gesetzt!
Schicke Info
zurück
Skript zur Vorlesung Datenbanken VertiefungSeite 77
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
INITIALIZE () =
DECLARE
dept_in_database = VarChar(100) with NULL
ENDDECLARE
...
ON SetValue department =
BEGIN
dept_in_database = NULL;
SELECT :dept_in_database = dept
FROM department_table
WHERE dept = :department;
IF dept_in_database IS NULL THEN
CurFrame.InfoPopUp(
messagetext = 'Bad department value ' + department,
messagetype = MT_ERROR);
RESUME;
ENDIF;
END;
4.10.5.3 Löschen von User Events aus der Queue
Methode PurgeUserEvent der Klasse FrameExec.
Syntax:
int_var = FrameExecVar.PurgeUserEvent(
[EVENTNAME = varchar(256)]);
Return-Wert ist Anzahl der gelöschten Events. Ohne Eventname werden alle
Events für dieses Frame gelöscht.
4.10.5.4 Synchronisation
Warten auf ein spezifisches User Event mit der Methode WaitFor().
• Nur für Referenzvariable CurFrame aufrufbar
• Event darf nicht vom eigenen Frame kommen
• Andere inzwischen ankommende Events landen in der Queue
• Frame ist geblockt, bis Event kommt
• Messageparameter nur, wenn Returnvariable angegeben ist
• Anwendung: SendUserEvent zurück an anderes Frame als Acknowledgement
Syntax:
Event = CurFrame.WaitFor(EVENTNAME = varchar(256));
4.10.5.5 Datenbankevents
Erlauben es, daß eine Anwendung Statusinformation an andere Anwendungen schickt.
• Werden über SQL-Befehle erstellt
Skript zur Vorlesung Datenbanken VertiefungSeite 78
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Können von allen Applikationen derselben Datenbank benutzt werden
• 256 Byte Information kann verschickt werden
Um Datenbankevents zu nutzen:
• Erzeuge Datenbankevent mit SQL-Anweisung CREATE DBEVENT
• Benutze in der empfangenden Applikation die SQL-Anweisung
REGISTER DBEVENT, um Datenbankevents empfangen zu können.
• Schreibe in dem Frame-Script den Datenbankeventblock
• Benutze in der sendenden Anwendung die SQL-Anweisung RAISE
DBEVENT
Die SQL-Befehle (Eventname sei ev1):
• DBEvent erstellen
CREATE DBEVENT ev1;
• Löschen
DROP DBEVENT ev1;
• Rechte vergeben
GRANT RAISE, REGISTER ON DBEVENT ev1 TO PUBLIC;
• Registrierung einschalten
REGISTER DBEVENT ev1;
• Registrierung ausschalten
REMOVE DBEVENT ev1;
• Events versenden
RAISE DBEVENT ev1 'Text';
Wenn eine Anwendung ein RAISE DBEVENT ausführt, sendet die Anwendung das Ereignis und den damit verbundenen Text an das DBMS. Dieses
sendet das Ereignis daraufhin an jede Anwendung, die dafür registriert ist.
In Windows4GL pollen registrierte Anwendungen regelmäßig auf Datenbankevents. Die Pollrate ist definiert durch das DBEventPollrate Attribut des SessionObject. Für jedes Datenbankevent wird ein DBEventObject erzeugt, welches dem entsprechenden Frame zugestellt wird.
W4GL-Befehle:
• Events auswerten:
ON DBEVENT 'ev1' =
BEGIN
Feld1_efd = CurFrame.DBEvent.DBEventName;
Feld2_efd = CurFrame.DBEvent.DBEventOwner;
Feld3_efd = CurFrame.DBEvent.DBEventDatabase;
Feld4_efd = CurFrame.DBEvent.DBEventText;
Feld5_efd = CurFrame.DBEvent.DBEventTime;
END;
Skript zur Vorlesung Datenbanken VertiefungSeite 79
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Pollrate einstellen:
/* Default ist 30 sec */
CurSession.DBEventPollrate = 5;
• Event registrieren (i.a. in dem Initialisierungsblock des Frames)
REGISTER DBEVENT ev1;
• Event „raisen“
RAISE DBEVENT ev1 'Text';
4.11 System Referenz Variablen
4.11.1 CurFrame
• Referenz auf das aktuelle Frame.
• Instanz der Klasse FrameExec
Attribute (nicht alle):
• CurMode
Augenblicklicher Frame-Modus:
FM_READ, FM_UPDATE, FM_QUERY, FM_USER1..3
Änderung dieses Feldwertes hat Auswirkungen auf Biases!
callframe framename() WITH CurMode=FM_READ;
• TriggerField
Feld, welches den augenblicklichen Event erzeugt hat (z.B. Entry- und
Exit-Events, ChildEntry und -Exit)
• OriginatorField
Auslösendes Feld, welches in dem Event-Block vorkommt, der den Code
für den augenblicklichen Event enthält:
ON CLICK TestRadioField,
ON CLICK TestMenuList =
BEGIN
IF CurFrame.OriginatorField = FIELD(TestRadioField) THEN
TestMenuList = TestRadioField;
ELSE TestRadioField = TestMenuList;
ENDIF;
...
END;
• InputFocusField
Feld des Frames, welches augenblicklich den Input-Fokus hat.
• TargetField
Exit: Nächstes Feld, Entry: Aktuelles Feld
• PreviousField
Entry: Feld, welches zuvor Input-Fokus hatte, Exit/Menu: NULL
• TopForm
Enthält die mit dem Frame verknüpfte Form (d.h. alle Felder ohne Menü). Anwendungen:
CurFrame.TopForm.HasDataChaged;
/* Attribut */
CurFrame.TopForm.SetToDefault();
/* Methode */
Skript zur Vorlesung Datenbanken VertiefungSeite 80
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• ParentFrame
• BgColor, BgPattern
• WindowTitle, HasScrollBars, IsResizable
• WindowPlacement
WP_SCREENRELATIVE, WP_SCREENCENTERED, WP_INTERACTIVE,
WP_PARENTRELATIVE, WP_PARENTCENTERED, WP_FLOATING
INITIALIZE (relx = Integer, lely = Integer) =
...
IF CurFrame.InputFocusField IS NOT NULL THEN
relx = CurFrame.InputFocusField.AbsXLeft + 500;
rely = CurFrame.InputFocusField.AbsXBottom + 500;
ELSE
relx = 1000;
rely = 1000;
ENDIF;
callframe relframe (...)
WITH WindowPlacement = WP_PARENTRELATIVE,
WindowXLeft
= relx,
WindowYTop
= rely;
...
Methoden (nicht alle):
• Terminate()
• SendUserEvent, WaitFor, PurgeUserEvent
• Flush()
CurFrame.Flush() läßt alle offenen Änderungen im Frame erscheinen.
Normalerweise geschieht das erst am Ende des Event-Blocks.
• Alle ...Popup(..) Methoden, geerbt von ProcExec
4.11.2 CurProcedure
• Referenz auf die aktuelle Prozedur.
• Lokale Variable der Klasse ProcExec, Super Class von FrameExec.
• Attribut ObjectSource.
Anwendungsbeispiel:
/* Aufruf vom Frame */
callproc disp_message (msr = 'This is a Message');
...
/* und die Prozedur ... */
PROCEDURE disp_message(msg = VarChar(256)) =
BEGIN
CurProcedure.InfoPopup(messagetext = msg);
END;
• Methode Beep()
• Duplicate();
Skript zur Vorlesung Datenbanken VertiefungSeite 81
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Alle XxxxPopup(..) Methoden
4.11.3 CurSession
• Instanz der Klasse SessionObject.
• Ist die eigentliche Anwendung.
• Informationen zur Laufzeitumgebung (DEC, Motif)
Attribute:
• ScreenHeight un ScreenWidth (in 1/1000 inches), dasselbe auch in
Pixels.
• DBMSErrorPrinting
EP_NONE:
Keine Ausgabe,
EP_OUTPUT:
Nach Standard Output,
EP_INTERACTIVE: Interaktives Popup-Fenster.
Methode:
value = SessionObject.GetEnv(name = varchar);
Environment-Variablen.
4.12 Events
Man unterscheidet die folgenden Event-Typen
• Frame Events
• Field Events
• Menu Events
Events werden folgendermaßen bearbeitet:
1. Wenn das Event erzeugt wird, wird es an das Ende der Event-Queue der
Anwendung gesetzt
2. Erreicht das Event den Anfang der Warteschlange der Anwendung, wird
es an das Ende der Warteschlange des entsprechenden Frames gesetzt
3. Erreicht das Event den Anfang der Event-Queue des Frames, wird der
entsprechende Event-Block des Frames ausgeführt.
Die Reihenfolge der Abarbeitung der Events ist nicht notwendigerweise dieselbe wie die der Erzeugung der Events!
Grundsätzlich wird immer ein Event-Block fertig bearbeitet, bevor das nächste Event an die Reihe kommt.
Per Default sind während der Abarbeitung eines Event-Blocks alle offenen
Frames blockiert, so daß in der Zeit keine zusätzlichen Ereignisse erzeugt
werden können. Kann durch setzen von BlockFrames auf False geändert
werden.
4.12.1 Frame Events
Alle nicht-feldspezifische Events (Wechselwirkung des Benutzers mit dem
Frame-Fenster), alle User Events und DBEvents. Außerdem erhält das Frame von allen untergeordneten Feldern entsprechende Child-Events.
Beispiele:
• ON WindowClose =
Schließen einer Frame-Fensters
Skript zur Vorlesung Datenbanken VertiefungSeite 82
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• ON Terminate =
Beenden eines Frames und aller untergeordneten Frames (z.B. bei Parent-Frame ausgelöst)
• ON ChildEntry =
• ON UserEvent =
• ON DBEvent =
Die Ausführung eines Events kann durch Aufruf von Resume im EventBlock unterbrochen werden, z.B. auf WindowClose hin.
4.12.2 Field Events
Events, die speziell für ein Feld oder eine Feldgruppe spezifiziert sind.
Für die verschiedenen Objekte ist eine große Zahl von Events zugelassen.
• On Click ... =
Feld mit Bias FB_LANDABLE oder FB_CHANGEABLE
Definiert für:
ImageField
ImageTrim
SliderField
BarField
ScrollBarField
ButtonField
ToggleField
ListField
RadioField
OptionField
MenuButton
MenuToggle
MenuList
Bei Enumerated Fields wird Click Event bei jedem Click erzeugt, auch
wenn der Wert sich dabei nicht ändert. Sonst: SetValue.
Achtung: Für Help oder Cancel Aktionen „Not Validated“ setzen!
• ON DoubleClick ... =
Für alle Form Fields definiert, nicht für Menu Fields. Nicht für Felder
mit Bias FB_VISIBLE, nicht für Entry Fields mit FB_CHANGEABLE
DoubleClick Events folgen jeweils einem Click Event!
• ON ClickPoint ... =
Feld mit Bias FB_CLICKPOINT
Für alle Form Fields definiert, nicht für Menu Fields.
Gibt Koordinaten in 1/1000 Inch relativ zum oberen linken Punkt des
Empfängers:
INITIALIZE () =
DECLARE
x_coord_of_click = Integer,
y_coord_of_click = Integer,
country_name = VarChar(100)
ENDDECLARE
BEGIN
...
FIELD(mapfield).CurBias = FB_CLICKPOINT;
...
END;
...
Skript zur Vorlesung Datenbanken VertiefungSeite 83
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON ClickPoint mapfield =
BEGIN
x_coord_of_click = CurFrame.XStart;
y_coord_of_click = CurFrame.YStart;
country_name = CallProc convert_to_country(
x_point = x_coord_of_click,
y_point = y_coord_of_click,
map_height = FIELD(mapfield).Height,
map_width = FIELD(mapfield).Width);
CurFrame.InfoPopup(messagetext = 'Country clicked was '
+ country_name);
END;
• ON Details ... =
Feld mit dem Details-Button (mittl. Maustaste) angeklickt
Nicht für Menu Fields, nicht für Eingabefelder mit Input-Fokus und
FB_CHANGEABLE.
Funktioniert auch auf Hintergrund (Frame)
ON Details tblfield,
ON ChildDetails tblfield =
BEGIN
callframe generic_help(field='tblfield');
END;
• ON DragBox ... =
Feld mit Bias FB_DRAGBOX und Benutzer zieht Dragbox in dem Feld.
Liefert die Koordinaten der DragBox
• ON DragSegment ... =
Feld mit Bias FB_DRAGSEGMENT und Benutzer zieht ein Dragsegment
in dem Feld. Liefert Anfangs- und End-Koordinaten der Linie
• ON Entry ... =
Für alle skalaren Felder, nicht für Menu, Shape oder Composite Fields.
Nicht für Button und Enumerated Fields (per Default).
FocusBehaviour muß FT_TABTO oder FT_TAKEFOCUS sein.
Hauptanwendung bei Eingabefeldern:
ON Entry name_field =
BEGIN
message_field = 'Bitte Name eingeben!';
END;
Nicht für Table Fields geeignet; siehe dazu ChildEntry!
• ON Exit ... =
Wenn Anwender dabei ist, das Feld mit dem augenblicklichen Input Fokus zu verlassen. Triggered bevor der Input Fokus tatsächlich gewechselt hat.
Nicht definiert für Menu, Shape und Composite Fields.
Muß validierbar sein!
Wird auch getriggert, wenn Daten nicht verändert wurden (d.h. Anwender ist nur durch das Feld durch. Sonst SetValue!)
Beispiel: Ändere Tab-Reihenfolge:
Skript zur Vorlesung Datenbanken VertiefungSeite 84
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON Exit testfield =
BEGIN
IF testfield = 2 THEN
CurFrame.InputFocusField = FIELD(field2);
Resume;
ELSEIF testfield = 3 THEN
CurFrame.InputFocusField = FIELD(field);
Resume;
ENDIF;
END;
• ON InsertRow ... =
Table Fields:
ON InsertRow tblfield =
BEGIN
tblfield[].columnfld = fill_in_default(...);
END;
• ON Moved ... =
Feld mit Bias FB_MOVEABLE oder FB_FLEXIBLE und Benutzer bewegt
das Feld.
Selten verwendet.
• ON Properties ... =
Feld mit dem Properties-Button (rechte Maustaste) angeklickt, alle Form
Fields. Nicht für Menu Fields.
ON Properties tblfield,
ON ChildProperties tblfield =
BEGIN
callframe generic_help(field='tblfield');
END;
• ON Resized ... =
Feld mit Bias FB_RESIZABLE oder FB_FLEXIBLE und Benutzer ändert
die Größe des Feldes
• ON Scroll ... =
Click auf Scrollbar von Table Field ode Viewport.
• ON Select ... =
Feld mit einem Select-Bias und Benutzer selektiert das Feld.
Alle Form Fields, nicht für Menu Fields.
Eher ChildSelect.
• ON SelectionChanged ... =
Das SelectedList Attribut des FrameExec-Objekts hat sich geändert. Nur
im Frame Script spezifizierbar.
• ON Unselect ... =
Feld mit einem Select-Bias und Benutzer deselektiert das Feld
• ON SetValue ... =
Feld mit Bias FB_CHANGEABLE.
Erzeugung des Events wird verzögert, bis Feld verlassen wird.
U.a. nicht für Composite Fields.
Wurde das Event durch das Verlassen eines Eingabefeldes getriggert, so
Skript zur Vorlesung Datenbanken VertiefungSeite 85
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
kann Resume benutzt werden, um den neuen Wert ungültig werden zu
lassen.
INITIALIZE () =
DECLARE
dept_in_database = VarChar(100) WITH NULL
ENDDECLARE
...
ON SetValue department =
BEGIN
dept_in_database = NULL;
REPEATED SELECT :dept_in_database = dept
FROM department_table
WHERE dept = :department;
IF dept_in_database IS NULL THEN
CurFrame.InfoPopup(
messagetext = 'Bad department value ' + department,
messagetype = MT_ERROR);
Resume;
ENDIF;
END;
• On Terminate ... =
Frame und alle Subframes werden geschlossen.
Nur im Frame Script.
ON Terminate =
BEGIN
IF CurFrame.ConfirmPopup(messagetext='Save chages?')
= PU_OK THEN
/* Rette alle Änderungen */
ENDIF;
END;
Häufig kommt es bei einer Benutzerinteraktion zu einer Kette von Events
(Event Chains). Wird z.B. ein Entry Field A verlassen, indem ein anderes
Entry Field B angeclickt wird (oder durch Tab), so kommt es zu der folgenden Event-Kette:
1. SetValue Event für Feld A
2. Exit Event für Feld A
3. Entry Event für Feld B
Oder: Jedesmal, wenn ein Benutzer ein Feld selektiert:
1. UnSelect Event für das vorige Feld
2. Select Event für das neue Feld
3. SelectionChanged Event für das Frame
Hat ein bestimmtes Feld mehrere Eventblöcke zugeordnet, ist es wichtig die
Reihenfolge der Erzeugung der Events zu berücksichtigen.
Skript zur Vorlesung Datenbanken VertiefungSeite 86
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Eine andere wichtige Gruppe von Field Events sind die sog. Child Events.
Eine Aktion an einem Child Field ruft ein Child Event für das Parent Field
hervor.
Sei ein Button A in einer Subform X enthalten, so erzeugt ein Click auf den
Button A die folgende Sequenz:
1. Click Event für Button A
2. ChildClick Event für Subform X
3. ChildClick Event für das Frame
Dies ist auch die Reihenfolge, in der die Events in die Warteschlange der
Anwendung eingereiht werden.
Ein Beispiel für Child Events innerhalb eines Frame-Scripts:
ON ChildEntry =
BEGIN
CurFrame.TriggerField.BgColor = CC_PALE_CYAN;
END;
ON ChildExit =
BEGIN
CurFrame.TriggerField.BgColor = CC_PALE_BLUE;
END;
Bei einer Event Chain werden zunächst alle Child-Events für ein bestimmtes
Event in die Warteschlange eingereiht, erst dann kommt das nächste Event
der Kette.
Unser Beispiel von oben mit den beiden Entry-Fields:
Frame
Subform
Feld1
Feld2
1.
2.
3.
4.
5.
6.
7.
8.
9.
SetValue für Feld1
ChilSetValue für Subform
ChildSetValue für Frame
Exit für Feld1
ChildExit für Subform
ChildExit für Frame
Entry für Feld2
ChildEntry für SubForm
ChildEntry für Frame
• ON ChildKlick ... =
Für Composite Fields, wenn ein Child Field einen Click Event bekommen hat.
Beispiel:
Skript zur Vorlesung Datenbanken VertiefungSeite 87
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON ChildClick testtable[*].testcolumn =
BEGIN
/* Current row will reflect the row that contained */
/* the image that was clicked
*/
callframe ShowDetail(picture = testtable[].testcolumn);
END;
Anderes Beispiel: Zwei Image Trim Felder sollen auf Click hin invers
dargestellt werden. Fasse beide Felder in picture_subform zusammen:
ON ChildClick picture_subform =
BEGIN
FormField(CurFrame.TriggerField).IsReverse = TRUE;
END;
• ON ChildKlickPoint ... =
Wie oben!
• ON ChildDetails ... =
Analog! Anwendung: Selektion einer Reihe aus einer Tabelle.
Feld muß den Bias FB_LANDABLE haben!
Im folgenden Beispiel hat das Table Field testtable ein Feld object_name:
ON ChildDetails testtable =
BEGIN
IF FIELD(testtable).CurRow > 0 THEN
callframe EditRow( name = testtable[].object_name );
ELSE
/* Keine Zeile war ausgewählt */
ENDIF;
END;
• ON ChildDoubleClick ... =
Analog wie DoubleClick. Anwendung wie bei ChildDetails Event
• ON ChildEntry ... =
Nützlich für Entry Events für Entry Fields innerhalb von Spalten eines
Table Fields:
ON ChildEntry emptable[*].salary =
BEGIN
help_field = 'Gib Gehalt in Tausend DM ein';
END;
Bei Exit dann entsprechend:
ON ChildExit emptable[*].salary =
BEGIN
help_field = '';
END;
CurFrame.TriggerField.Name würde bei ChildEntry den Namen des genauen Feldes zurückgeben.
• ON ChildExit ... =
Beispiel: Wird die Zeile eines Table Fields verlassen? Wenn ja könnte eine Validierung durchgeführt werden.
Skript zur Vorlesung Datenbanken VertiefungSeite 88
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
ON ChildExit testtable =
BEGIN
IF FIELD(testtable).WhichRow(
cellfield = CurFrame.TriggerField) !=
(FIELD(testtable).WhichRow(
cellfield = CurFrame.TargetField) THEN
/* Das nächste Feld ist in einer anderen Zeile */
/* oder außerhalb des Table Fields
*/
...
ENDIF;
• ON ChildSetValue ... =
Beispiel:
ON ChildSetValue emptable[*].salary =
BEGIN
if emptable[].salary > 100000 THEN
CurFrame.InfoPopup(
message='Gehalt muß weniger als 100000 sein',
messagetype = MT_ERROR);
resume;
ENDIF;
END;
4.12.3 Menu Events
Alle Events für Menüs.
Menü-Felder haben Click Event definiert.
Menu Toggle und Menu List haben zusätzlich SetValue Event
Beispiele:
ON Click menu.datei.neu = ...
ON SetValue menu.hilfe_tgl = ...
4.12.4 Einschub
Dynamisches Initialisieren eines EnumFields:
INITIALIZE () =
DECLARE
i
= Integer,
tmp = VarChar(20)
ENDDECLARE
Skript zur Vorlesung Datenbanken VertiefungSeite 89
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
BEGIN
FIELD(Auswahl).ValueList.ChoiceItems.Clear();
i = 1;
REPEATED SELECT DISTINCT :tmp = Spalte
FROM Tabelle
WHERE ...
BEGIN
FIELD(Auswahl).ValueList.ChoiceItems[i].EnumText = tmp;
FIELD(Auswahl).ValueList.ChoiceItems[i].EnumValue = i;
i = i + 1;
END;
COMMIT;
FIELD(Auswahl).CurEnumValue = 3;
/* oder .CurEnumText = '...' */
FIELD(Auswahl).UpdChoiceList();
END;
Andere Möglichkeit:
...
FIELD(Auswahl).ValueList.AddTextItem(enumvalue=i,
textvalue=tmp);
...
4.13 Einbinden von Prozeduren und Funktionen
4.13.1 Allgemeines
• Definition im Component Catalog
(DB- und 3GL-Prozeduren werden hier nur bekannt gemacht)
• Einmal erstellte Prozedur kann aus jedem W4GL-Script der aktuellen Applikation aufgerufen werden
• Globale 4GL-Prozedur ist global in Anwendung; nicht frame-spezifisch.
Daher kann auf Feld-Namen NICHT Bezug genommen werden!
• Lokale 4GL-Prozedur wird lokal in einem Frame-, Field- oder ProzedurSkript definiert. Aufrufbar in dem definierenden Skript oder in Skripts
untergeordneter Felder
• Vier
-
Typen von Prozeduren:
4GL-Prozeduren (W4GL-Code, in der Applikation), global und lokal
Datenbankprozeduren (SQL-Code, in der Datenbank)
3GL-Prozeduren (C, Cobol, Fortran, Pascal, ...)
4.13.2 Aufrufsyntax
4GL-Prozeduren:
[ReturnVar=] CALLPROC Prozedurname
[ (Parm = Ausdr | ByRef(Variable)
{, Parm = Ausdr | ByRef(Variable)} ) ]
Skript zur Vorlesung Datenbanken VertiefungSeite 90
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Datenbank-Prozeduren:
[IntegerVar=] CALLPROC Prozedurname
[ (Parm = Ausdr
{, Parm = Ausdr} ) ]
4.13.3 4GL Prozeduren
• Globale Prozeduren erzeugt mit dem Procedure Editor
• Lokale Prozeduren werden in einem Frame-, Field- oder Prozedur-Skript
definiert; die Prozedur wird mit Hilfe der PROCEDURE-Anweisung implementiert (nach allen Event-Blöcken).
• Es können Parameter und lokale Variablen spezifiziert werden.
• Parameterübergabe = Setzen von Werten von lokalen Variablen
• ByRef-Übergabe ist möglich
• Frame-Felder sind nicht zugreifbar
• Folgende Komponeten können aufgerufen werden:
- Frames
- 4GL-, 3GL-, Datenbank-Prozeduren
Beispiel:
PROCEDURE insert_video_row(
video_list = ARRAY OF VIDEO_ROW,
title = VarChar(50) NOT NULL,
row = Integer NOT NULL ) =
BEGIN
...
END;
Aufruf:
CALLPROC insert_video_row(video_list = vlist,
title = video.title, row = ByRef(i));
Beispiel für eine lokale Prozedur:
INITIALIZE () =
DECLARE
load_data = procedure;
...
ENDDECLARE
BEGIN
callproc load_data;
END;
PROCEDURE load_data() =
DECLARE
i = integer
ENDDECLARE
/* Vorwärts Deköaration */
Skript zur Vorlesung Datenbanken VertiefungSeite 91
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
BEGIN
COMMIT;
/* Start a new transaction */;
parttable.Clear();
/* Clear out array */
i = 1;
SELECT :parttable[i].partno = partno,
:parttable[i].partno_save = partno,
:parttable[i].short_desc = short_desc
FROM
part
BEGIN
i = i + 1;
END;
END;
4.13.4 Datenbankprozeduren
• Sind Objekte der Datenbank
• Formuliert in SQL
• Ausführungsrecht reicht
• Aufruf wie 4GL-Prozeduren, aber keine ByRef-Übergabe möglich
• Return-Wert ist immer Integer
• Vorteil: Geringe Kommunikation zwischen Client und Server: Bessere
Performance.
Einsetzbar zur Gewährleistung der Datenintegrität.
• Aufrufmöglichkeit auch durch Datenbank-Regeln (Rules)
Syntax zum Erstellen:
[CREATE] PROCEDURE Prozedurname
[ (ParmName [=] ParmTyp
{, ParmName [=] ParmTyp } ) ]
= | AS
[ DECLARE
VarName {, VarName } [=] VarTyp;
{, VarName {, VarName } [=] VarTyp;} ]
BEGIN
statement {; statement} [;]
END;
Beispiel:
/* DB-Prozedur zum Löschen aus der Tabelle mitarbeiter */
CREATE PROCEDURE DelMitarbeiter
(p_persnr = Integer NOT NULL) AS
DECLARE
p_abteilung = VarChar(10) NOT NULL;
p_region
= Char(5)
NOT NULL;
Skript zur Vorlesung Datenbanken VertiefungSeite 92
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
BEGIN
SELECT abteilung, region INTO p_abteilung, p_region
FROM mitarbeiter
WHERE persnr = :p_persnr;
IF iirowcount < 1 THEN
return -1;
ENDIF;
DELETE FROM mitarbeiter
WHERE persnr = :p_persnr;
IF iirowcount != 1 OR iiErrorNumber != 0 THEN
return -1;
ENDIF;
UPDATE abteilung
SET mitarb = mitarb - 1
WHERE abteilung = :P_abteilung
AND bezirk = :p_region;
IF iiErrorNumber != 0 THEN
return -1;
ENDIF;
return 1;
END;
/* Alles o.k. */
4.14 Einige Ergänzungen zu SQL
4.14.1 Spezielle Ingres Konstanten
now
Aktuelles Datum und Zeit
select date('now')
today
Aktuelles datum
select date('today')
null
undefinierter oder unbekannter Wert
user
Aktueller User-ID
4.14.2 Zeit Intervalle
Beispiele:
date('today') + date('2 years 2 months');
date('now')
+ date('12 hours 30 minutes');
Anzahl der Tage seit 1.1.1900:
num_days = int4(interval('days', 'today' - date('1/1/00')))
Skript zur Vorlesung Datenbanken VertiefungSeite 93
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Zurück:
(date('1/1/00') + concat(char(num_days), ' days'))
4.14.3 Funktionen zur Typkonversion
Name
Operand Typ
Resultat Typ
Beschreibung
c(expr)
jeder
c
Jeder Wert zu c
String
char(expr)
jeder
char
Jeder Wert zu
char String
date(expr)
c, char, varchar,
text
date
Ergebnis ist
interne Datumsdarstellung
dow(expr)
date
c
Wochentag, z.B.
'Mon', Länge 3
float4(expr),
float8(expr)
c, char, varchar,
float4 bzw. float
text, float, money,
alle Integers
Ergebnis Gleitkomma
hex(expr)
c, char, varchar,
text
Zweimal so lang
wie ArgumentString:
hex('A') liefert '61'
int1(exp),
int2(exp),
int4(exp)
c, char, varchar,
integer1 bzw.
text, float, money, smallint bzw.
alle Integers
integer
Dezimalbrüche
werden
abgeschnitten
money(expr)
c, char, varchar,
text, float, alle
Integers
money
Interne money
Darstellung, Dezimalbrüche evtl.
gerundet
text(expr)
jeder
text
text String ohne
trailing blanks von
c oder char
Strings
varchar(expr)
jeder
varchar
varchar String
ohne trailing
blanks von c oder
char Strings
varchar
4.14.4 Numerische Funktionen
Name
Operand Typ
Resultat Typ
abs(n)
alle numerischen und money
wie n
atan(n)
alle numerischen und money
float
cos(n)
alle numerischen und money
float
exp(n)
alle numerischen und money
float
Skript zur Vorlesung Datenbanken VertiefungSeite 94
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
log(n)
alle numerischen und money
float
mod(n,b)
integer, smallint, integer1
wie b
sin(n)
alle numerischen und money
float
sqrt(n)
alle numerischen und money
float
Argumente der Winkelfunktionenin Radian. Konvertierung:
radians = degrees/360 * 2 * pi
4.14.5 String Funktionen
Name
Resultat Typ
Beschreibung
concat(c1,c2)
jeder Character Typ Resultat Länge ist Summe der Einzellängen. c und char Ergebnisvariablen werden evtl. mit Blanks
aufgefüllt
left(c1,len)
jeder Character Typ Erste len Zeichen. c und char Ergebnisvariablen haben dieselbe Länge wie c1 padded mit Blanks
length(c1)
smallint
Länge des Strings, für c und char
ohne trailing Blanks
locate(c1,c2)
smallint
Stelle des ersten Vorkommens von
c2 in c1. Wird c2 nicht gefunden, ist
das Resultat size(c1)+1.
lowercase(c1)
jeder Character Typ zu lower case
pad(c1)
varchar, text
right(c1,len)
jeder Character Typ Erste len Zeichen von rechts. Blanks
werden nicht zuvor entfernt.
shift(c1,nshift)
jeder Character Typ Verschiebt String nshift Stellen nach
rechts (nshift>0) oder links (nshift<0)
size(c1)
smallint
Deklarierte (maximale) Länge
squeeze(c1)
varchar, text
Komprimiert „white space“. Entfernt
am Anfang und Ende. Dazwischen
jeweils max. 1 Blank
trim(c1)
varchar, text
Schneidet trailing Blanks ab
uppercase(c1)
jeder Character Typ zu Großbuchstaben
Fügt Blanks auf maximale Länge ein
charextract(c1,n) jeder Character Typ Resultat ist das n-te Byte. Ist n größer als Stringlänge: Blank
4.14.6 Datums-Funktionen
Datums-Units: Second, Minute, Hour, Day, Week, Month, Quarter, Year.
Skript zur Vorlesung Datenbanken VertiefungSeite 95
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Name
Resultat Typ
Beschreibung
date_trunc(unit,
date)
date
Datum abgeschnitten auf unit
Date_part(unit,
date)
integer
Gibt Komponente (unit) des Datums
als Integer
date_gmt(date)
Jeder Character Typ GMT-Format:
yyyy_mm_dd hh:mm:ss GMT
interval(unit,
date_interval)
float
_date(s)
Jeder Character Typ 9 Character String mit Datum s Sekunden nach 1.1.1970 GMT
_time(s)
Jeder Character Typ 5 Character String mit Zeit s Sekunden nach 1.1.1970 GMT
Gibt Komponente (unit) des Zeitintervalls als Float.
4.14.7 Aggregat-Funktionen
Liefert einen einzelnen Wert aufgrund des Inhalts einer Spalte zurück. Können in select, insert, update und delete SQL-Befehlen benutzt werden. Am
meisten in select.
SELECT :sum_efd = sum(employee.salary)
FROM employee
WHERE dept = 23;
Die Aggregat-Funktionen von SQL:
Name
Resultat Typ
Beschreibung
count
integer
Anzahl vorkommende Sätze
sum
integer, float, money, date (interval)
Gesamtsumme der Spalte
avg
float, money, date
(interval)
Mittelwert (sum/count)
max
wie das Argument
Maximal-Wert der Spalte
min
wie das Argument
Minimum-Wert der Spalte
4.14.8 Fehlerbehandlung
Nach jeder Datenbankanweisung sollte die Fehlerfreiheit der letzten Aktion
überprüft werden.
Zwei Attribute der DBSessionObject Klasse gestatten die Überprüfung von
Fehlerbedingungen: ErrorNumber und DBMSError geben Auskunft über
den Verlauf der letzten SQL-Anweisung. Sind die primären Mittel zur Überprüfung auf Fehler.
ErrorNumber und DBMSError werden nach jedem SQL-Befehl gesetzt.
• DBMSError enthält den lokalen Fehlercode des zugrunde liegenden
Datenbanksystems, z.B. Ingres oder DB2.
Skript zur Vorlesung Datenbanken VertiefungSeite 96
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• ErrorNumber ist der generische Fehlercode, den Ingres unabhängig vom
dahinterstehenden DBMS aufgrund dessen lokalen Fehlercodes zuweist
(auch für Ingres-Fehler).
Z.B. weist Ingres einem time-out Fehler die lokale Fehlernummer 4702 zu.
Andere DBMSe mögen dafür einen anderen Fehlecode benutzen. Aber Ingres
bildet alle diese lokalen Fehler auf denselben generischen Fehlecode ab.
Überprüfung des generischen Fehlercodes macht die Anwendungen portabel.
Bei fehlerfreier Ausführung des letzten Datenbankbefehls werden beide Variablen auf 0 gesetzt.
Eine Möglichkeit, diese Variablen in einer Prozedur weiter auszuwerten:
PROCEDURE dbms_error_message () =
BEGIN
IF CurFrame.DBSession.ErrorNumber != 0 THEN
return 'Fehler Code ist ' +
VarChar(CurFrame.DBSession.ErrorNumber) +
'. Spezifischer DBMS Fehler ist ' +
VarChar(CurFrame.DBSession.DBMSError);
ELSE
return '';
ENDIF;
END;
Aufruf:
IF CurFrame.DBSession.ErrorNumber != 0 THEN
message 'Es ist ein Fehler aufgetreten: ' +
dbms_error_message();
ENDIF;
Mit dem Attribut DBMSErrorPrinting der Systemklasse SessionObject kann
festgelegt werden, in welcher Form SQL-Fehler am Bildschirm erscheinen:
• EP_NONE
keine Ausgabe
• EP_OUTPUT
im Standardoutput Fenster (Unix-Shell Fenster)
• EP_INTERACTIVE in Popup-Fenster (Default)
Eine weitere wichtige Hilfe ist die Systemvariable IIRowCount. Sie enthält
die Anzahl der von dem letzten SQL-Befehl „betroffenen“ Zeilen.
• Nach einem SELECT enthält sie die Anzahl der Reihen der Antworttabelle
• Nach einem UPDATE bedeutet IIRowCount=0, daß kein Update durchgeführt wurde, weil z.B. keine Reihe der Tabelle der WHERE-Bedingung
entspricht.
Über den Befehl INQUIRE_SQL kann man sich den Status der zuletzt ausgeführten SQL-Anweisung holen:
Skript zur Vorlesung Datenbanken VertiefungSeite 97
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
...
IF CurFrame.DBSession.ErrorNumber != 0 THEN
ROLLBACK;
Message 'Es hat einen Fehler gegeben!';
INQUIRE_SQL( :v_fehler = ERRORNO,
:v_text
= ERRORTEXT,
:v_anzahl = ROWCOUNT );
ENDIF;
ERRORNO ist dabei die generische Fehlernummer.
Eine generelle Fehlerbehandlungsroutine:
Zunächst Teil eines Scripts aus der Video-Applikation:
UPDATE v_video ...... ;
IF error_handler(frm=CurFrame, retry_evt='Retry') !=
ER_OK THEN
resume;
ENDIF;
...
Die Fehlerbehandlungsroutine prüft zunächst, ob ein Deadlock aufgetreten
ist. In diesem Fall sendet die Prozedur ein User-Event an das Frame zurück,
um die Transaktion neu zu beginnen. War ein anderer Datenbank-Fehler
aufgetreten, so wird der Fehler in einem Pop-up Fenster angezeigt.
Der Fehler oder die ER_OK Bedingung wird zurückgegeben.
PROCEDURE error_handler (
frm
= FrameExec,
retry_evt = VarChar(32),
) =
DECLARE
err_no
ENDDECLARE
/* Calling Frame */
/* Event to signal retry,
if deadlock occured */
= Integer NOT NULL
BEGIN
err_no = CurProcedure.DBSession.ErrorNumber;
IF err_no = 49000 THEN
/* Deadlock */
message 'Deadlock occured';
frm.SendUserEvent(retry_evt);
ELSEIF err_no != Er_OK THEN
message 'DBMS error ocurred: ' + dbms_error_message();
ENDIF;
return err_no;
END;
4.14.9 Transaktionen
Eine Transaktion besteht aus einer oder mehreren Datenbankanweisungen,
die eine logisch unteilbare Arbeitseinheit ausführen.
Skript zur Vorlesung Datenbanken VertiefungSeite 98
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Beispiel: Ein Mitarbeiter soll eine neue Personalnummer bekommen. Dazu
müssen außer in der Tabelle mitarbeiter auch Sätze in der Tabelle arbeiten
geändert werden. Nur wenn beide Tabellen aktualisiert wurden, ist die Datenbank wieder konsistent.
UPDATE mitarbeiter
SET m_nr = 39831
WHERE m_nr = 10102;
UPDATE arbeiten
SET m_nr = 39831
WHERE m_nr = 10102;
Commit;
Eine Transaktion beginnt automatisch mit der ersten Datenbankanweisung
der Anwendung bzw. der Session oder nach einer vorherigen Commit oder
Rollback-Anweisung.
Per Default dauert die Transaktion solange, bis eine ausdrückliche Commit
oder Rollback-Anweisung gegeben wird oder bis die Session oder die Anwendung beendet wird.
Alle Locks, die während der Transaktion in Kraft traten, werden bis zum Ende der Transaktion gehalten. Alle Änderungen an der Datenbank werden erst
nach Ende der Transaktion für andere Benutzer sichtbar.
Mit Hilfe der SQL-Anweisung SAVEPOINT savepointname können bestimmte
Punkte in dem Programm gekennzeichnet werden. In diesem Fall ist dann
ein partielles Rollback bis zu einem dieser Punkte möglich.
INSERT INTO emp_table VALUES (...);
UPDATE ... ;
SAVEPOINT first;
INSERT ... ;
DELETE ... ;
if error on delete
ROLLBACK TO first;
ELSEIF other errors
ROLLBACK;
...
Man kann Ingres anweisen, jede einzelne Datenbankanweisung automatisch
zu „commiten“.
set autocommit on | off
Default ist off. Mit on sollte man sehr vorsichtig sein!
Transaktionen werden durch die Anwendung abgebrochen durch
• die ROLLBACK-Anweisung oder
• ein abgelaufenes Time-out, falls es aktiviert ist.
In bestimmten Fällen beendet Ingres selbst eine Transaktion:
• Bei einem Deadlock wird die den Deadlock erzeugende Transaktion abgebrochen
Skript zur Vorlesung Datenbanken VertiefungSeite 99
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Der Transaction log file kann voll sein
• Ein Datenbankfehler ist aufgetreten
Im letzteren Fall entscheidet die Wahl von
set session with on_error =
rollback statement | transaction
ob nur die letzte Datenbankanweisung oder die ganze Transaktion zurückgerollt wird. Default ist statement.
In bestimmten Fällen wird immer die Transaktion zurückgerollt:
• Deadlock
• Forced Abort
• Lock quota exceeded
Anhand von
SELECT DBMSInfo('transaction_state')
oder
inquire_sql(in_transact = transaction);
stellt man fest, ob die Transaktion durch Ingres abgebrochen wurde.
4.14.10 Regeln (Rules
(Rules))
Benutzerdefinierter Mechanismus, der bei bestimmten Veränderungen an
der Datenbank eine Datenbank-Prozedur aufruft.
Typen von Datenbankveränderungen:
• Insert-, Update- oder Delete-Operation in einer bestimmten Tabelle
• Update einer oder mehrerer Spalten einer Tabelle
• Änderungen, die einer bestimmten Bedingung zwischen mehreren
Spalten einer Tabelle genügen
Erzeugt mit
CREATE RULE
wieder gelöscht mit
DROP RULE
Anwendungen:
• Sicherstellung der Referentiellen Integrität
• Sicherstellung anderer, allgemeiner Integritätsregeln
• Sicherstellung anderer Regeln
4.14.10.1 Sicherstellung der Referentiellen Integrität
Primärschlüssel - Fremdschlüssel Problematik.
Tabellen abteilung und mitarbeiter. Spalte abt_nr ist Primärschlüssel in abteilung und Fremdschlüssel in mitarbeiter (Master-Detail Beziehung).
Fremdschlüsselwerte müssen sich auf einen identischen Primärschlüssel
beziehen; dieser muß existieren.
Skript zur Vorlesung Datenbanken VertiefungSeite 100
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
Diese Bedingung kann von einer Datenbankregel beim Ändern von Fremdschlüsseln oder Einfügen entsprechender Sätze mit Fremdschlüsseln überprüft werden. Bei Verstoß kann die Regel unterschiedlich reagieren:
• Der Fremdschlüsselwert, der die Integritätsregel verletzt, wird abgewiesen (rejected).
D.h. es muß ein rollback geschehen. Dabei hilft die raise error Anweisung. Durch sie wird das DBMS und die Anwendung informiert, daß die
Anweisung, die die Regel gefeuert hat, eine Integritätsregel verletzt hat
und daher zurückgewiesen wurde.
• Die zweite Möglichkeit ist, den Fremdschlüssel ohne passenden Primärschlüssel statt des geforderten Wertes mit NULL zu belegen (nullify).
Man kann sich auch andere Möglichkeiten denken.
• Die dritte Möglichkeit wird Kaskadieren (cascading) genannt. Handelt es
sich um eine Insert- oder Update-Operation, so kann man u.U. den
Fremdschlüssel auch als Primärschlüssel verwenden, d.h. diesen ändern oder einen neuen Satz anlegen.
Umgekehrt kann man auch entsprechende Reaktionen für die Sätze mit den
passenden Fremdschlüsselwerten definieren, wenn ein Primärschlüssel geändert oder die entsprechende Reihe ganz gelöscht wird.
• Auch hier kann eine Änderung zurückgewiesen werden.
• Beim Löschen werden in allen Sätze mit passenden Fremdschlüsseln
diese auf NULL gesetzt
• Oder man nutzt die Möglichkeit des Kaskadierens. Beim Ändern werden
auch alle zugehörigen Fremdschlüsselwerte geändert. Beim Löschen
werden alle Sätze mit passenden Fremdschlüsseln ebenfalls gelöscht.
4.14.10.2 Sicherstellung anderer, allgemeiner Integritätsregeln
Angenommen, in unserer Tabelle abteilung sei eine weitere Spalte anz_ma
mit der Anzahl der Mitarbeiter in der Abteilung (wenn auch redundante Information).
Wenn immer ein neuer Mitarbeiter der Abteilung zugeordnet wird (oder diese
verläßt), soll diese Spalte aktualisiert werden. Dies kann eine Regel leisten,
unabhängig von der Anwendungslogik.
CREATE RULE neuer_ma AFTER INSERT INTO mitarbeiter
EXECUTE PROCEDURE neu_ma(abt_nr = mitarbeiter.abt_nr);
Jedesmal, wenn ein neuer Mitarbeiter der Tabelle mitarbeiter hinzugefügt
wird, wird die Regel automatisch die Tabelle abteilung aktualisieren.
4.14.10.3 Sicherstellung anderer Regeln
Man kann Regeln dazu benutzen, bestimmte Geschäftsregeln in der Datenbank zu verankern.
Mit der folgenden Regel wird sichergestellt, daß bestimmte Reihen einer Tabelle nur von einem bestimmten Anwender eingefügt oder gelöscht werden
können:
Skript zur Vorlesung Datenbanken VertiefungSeite 101
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
CREATE RULE check_auth
AFTER INSERT, DELETE FROM opcodes
WHERE opcodes.scope = 'share' AND user != 'system'
EXECUTE PROCEDURE reject_and_log_operation;
Oder das Beispiel vom Nachbestellen:
CREATE RULE reorder_item
AFTER UPDATE(in_stock) OF items
WHERE items.in_stock < 100
EXECUTE PROCEDURE reorder_items(id = items.id,
items_left = items.in_stock);
4.14.10.4 Beispiel
Hiermit wird die Integrität zwischen Mitarbeiter, Manager und Department
beim Einfügen neuer Mitarbeiter oder bei einer Änderung für einen Mitarbeiter sichergestellt:
• Die Fremdschlüssel in die Manager und Department Tabellen müssen
gültig sein
• Der Manager muß auch zu der neuen Abteilung des
ren
Die Regel:
CREATE RULE check_emp AFTER INSERT, UPDATE
EXECUTE PROCEDURE valid_mgr_dept(ename =
mname =
dname =
Mitarbeiters gehö-
OF employee
new.name,
new.mgr,
new dept);
Die Datenbankprozedur:
CREATE PROCEDURE valid_mgr_dept(ename VarChar(30),
mname VarChar(30),
dname VarChar(10)) AS
DECLARE
msg
VarChar(80) NOT NULL;
check_val Integer;
mgr_dept VarChar(10);
Skript zur Vorlesung Datenbanken VertiefungSeite 102
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
BEGIN
SELECT Count(*) INTO :check_val FROM manager
WHERE name = :mname;
IF check_val = 0 THEN
msg = 'Error 1: Manager "' + :mname + '" not found';
RAISE ERROR 1 :msg
RETURN;
ENDIF;
SELECT Count(*) INTO :check_val FROM dept
WHERE name = :dname;
IF check_val = 0 THEN
msg = 'Error 2: Department "' + :dname + '" not found';
RAISE ERROR 2 :msg
RETURN;
ENDIF;
SELECT dept INTO :mgr_dept FROM manager
WHERE name = :mname;
IF mgr_dept != dname THEN
msg = 'Error 3: Manager "' + :mname +
'" and department "' + :dname +
'" do not match';
RAISE ERROR 3 :msg
RETURN;
ENDIF;
msg = 'Employee "' + :ename + '" updated ' +
'(mgr = "' + :mname + ', ' + dname +'")';
MESSAGE :msg;
INSERT INTO emplog VALUES (:msg);
END;
RAISE ERROR errornumber [errortext]
erzeugt einen Datenbankfehler.
Wurde die Datenbankprozedur durch eine Regel gefeuert, so rollt Ingres alle
Änderungen der Original-Datenbankanweisung, die die Regel auslöste, und
alle Änderungen, die die Prozedur bis dahin durchgeführt hat, zurück.
errornumber ist eine lokale DBMS-Fehlernummer. Die generische Fehlernummer ist 41300. errornumber und errortext werden an die Anwendung zurückgegeben. Aber nur errortext wird angezeigt.
Regeln für Fehlerzustände in Verbindung mit Rules:
• SQL-Befehl und Prozedur, die durch Rule gestartet wird, sind eine Einheit! Daher kein Commit oder Rollback in einer DB-Prozedur, die durch
eine Rule initiiert wird!
Skript zur Vorlesung Datenbanken VertiefungSeite 103
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
• Ein SQL-Befehl kann mehrere Rules auslösen. Die Reihenfolge ist jedoch undefiniert!
• Bei Update und Delete feuert die Rule bei jedem betroffenen Satz.
• Eine von einer Rule gestartete DB-Prozedur kann wieder eine Rule feuern! Nach 20 Level bricht Ingres die Kette ab!
• Tritt ein Fehler in Verbindung mit einer Rule auf, so erleidet der gesamte auslösende SQL-Befehl einen fatalen Fehler: Rollback SQL-Befehl
und Rule
• Fehler entsteht auch durch „raise error“
4.15 Aufruf von Subsystemen
4.15.1 Ingres-Subsysteme
Das Kommando CALL ruft ein Ingres-Subsystem oder eine Applikation mit
oder ohne Parametern auf.
CALL subsystem ([parmname1 = wert1, ...]);
• Alle Frames werden geblockt bis das aufgerufene Subsystem beendet
wird
• Implizites Commit ohne Warnung, wenn aus einer offenen Transaktion
aufgerufen
• Wenn in der laufenden Applikation kein Connect zu einer Datenbank
besteht, kann nur RUNIMAGE aufgerufen werden.
Subsystem Typen:
• CALL APPLICATION
ABF-Anwendung
• CALL ISQL
Interactive SQL
• CALL SQL
SQL Terminal Monitor
• CALL QBF
Query-By-Forms
• CALL REPORT
Report-Writer
• CALL RUNDBAPP
In derselben Datenbank gespeicherte
Windows4GL-Anwendung
• CALL RUNIMAGE
Windows4GL-Anwendung in Runimage-Form
Beispiele:
COMMIT;
CALL rundbapp(APPLICATION
= 'inventory',
STARTCOMPONENT = 'parts');
COMMIT;
CALL runimage(FILENAME
= 'mitarbeiter',
STARTCOMPONENT = 'hauptmenu');
COMMIT;
CALL qbf();
Skript zur Vorlesung Datenbanken VertiefungSeite 104
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
COMMIT;
CALL report(NAME = 'mitarbeiter',
MODE = 'column');
4.15.2 Unix-Aufrufe
Mittels des CALL SYSTEM Kommandos werden Betriebssystem-Kommandos
aufgerufen.
• Können im Hintergrund oder Vordergrund laufen (bei Unix). Hintergrund: Windows4GL-Anwendung bleibt aktiv!
• Kein Returncode möglich
Syntax und Beispiele:
CALL SYSTEM [cmdstring];
CALL SYSTEM 'vi datei.txt';
CALL SYSTEM 'runimage tetris.img';
CALL SYSTEM 'xcalc &';
4.16 Hilfsfunktionen für OpenROAD-Anwendungen
4.16.1 Erstellen eines Images der Anwendung
Speicherung der lauffähigen Anwendung in einer normalen Unix-Datei. Läuft
mit wesentlich besserer Performance.
makeimage [-uusername] [-f] database application file
Parameter:
-f Forced Recompilation: Alle Komponenten werden neu übersetzt
Starten einer solchen Anwendung:
runimage file parameters
4.16.2 Starten einer Anwendung in einer Datenbank
Ohne OpenROAD aufzurufen.
rundbapp database application parameters
4.16.3 Kopieren einer Anwendung in eine Textdatei
Die ganze Anwendung oder Komponenten von ihr. In Verbindung mit der
Import-Funktion geeignet, um eine Anwendung auf eine andere Plattform zu
portieren:
exportapp [-ccomponent] database application file
Das Gegenstück:
importapp [-ccomponent] database application file
Hierbei gibt es noch mehrere mögliche Parameter, s. Handbuch!
Skript zur Vorlesung Datenbanken VertiefungSeite 105
FH Wiesbaden, FB Informatik, Prof. Dr. Dreher, SS 1996
4.16.4 Report einer Anwendung
Erzeugt eine Dokumentation der Anwendung, z.B. Liste aller Skripts:
documentapp [-ccomponent] [-s] database application file
Parameter:
-s Nur die 4GL-Quellcodes
-a Alles (alle Attribute aller Felder): Sehr umfangreich
Herunterladen