Blackfish SQL Copyright© 2008 Embarcadero Technologies, Inc. Alle Rechte vorbehalten. Blackfish SQL Inhalt Vorwort 1 Übersicht 3 Systemarchitektur 7 Verbindungen aufbauen 25 Administration von Blackfish SQL 33 Sicherheitsfunktionen von Blackfish SQL 37 Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden 43 Trigger in Blackfish SQL-Tabellen verwenden 57 Gespeicherte Prozeduren - Referenz 61 SQL-Referenz 77 Blackfish SQL-Anwendungen optimieren 129 Deployment von Blackfish SQL-Datenbankanwendungen 137 Fehlersuche 141 Index a iii 1 Blackfish SQL 1 1 Vorwort In diesem Vorwort wird das Handbuch beschrieben, werden technische Ressourcen aufgeführt und Kontaktinformationen zu CodeGear zur Verfügung gestellt. Zielgruppe Dieses Dokument ist geeignet für: • Entwickler, die Blackfish SQL-Datenbankanwendungen implementieren • Systemadministratoren, die für die Installation, das Deployment und die Pflege von Blackfish SQL-Datenbanken verantwortlich sind Benutzer von Blackfish SQL für Windows benötigen folgende Praxiskenntnisse: • Delphi-, C++-, C#- oder VB.NET-Programmierung • Grundlagen in dbExpress 4 oder ADO.NET 2.0 • Grundlagen in SQL Benutzer von Blackfish SQL für Java benötigen folgende Praxiskenntnisse: • Java-Programmierung • DataExpress • JDBC • SQL Konventionen in der Dokumentation Dieses Dokument verwendet die folgenden typografischen Konventionen: Schriftart oder Symbol Verwendung Schrift mit fester Breite Computer-Ausgabe, Dateien, Verzeichnisse, URLs und Code-Elemente wie z. B. Befehlszeilen, Schlüsselwörter, Funktionsnamen und Code-Beispiele Kursive Breite Schrift mit fester Parameternamen und Variablen Fett GUI-Elemente, Hervorhebungen, Abschnittsunterüberschriften Kursiv Buchtitel, neue Begriffe 1 Blackfish SQL 1 Unterstrichene Schrift 1 Hyperlink Technische Online-Ressourcen Allgemeine Informationen finden Sie unter: http://www.codegear.com/Blackfish SQL. Technische Informationen und Beiträge der Community finden Sie unter: http://cdn.codegear.com/Blackfish SQL. In den folgenden Newsgroups können support.codegear.com/newsgroups/directory. Sie sich mit anderen Blackfish SQL-Benutzern austauschen: CodeGear-Support CodeGear bietet Support für Blackfish SQL in verschiedenen Varianten an. Weitere Informationen zur Presales-Unterstützung, Unterstützung bei der Installation und einer Vielzahl von technischen Support-Möglichkeiten finden Sie auf den folgenden Websites: http://support.codegear.com. Wenn Sie Blackfish SQL bereitstellen möchten, müssen Sie eine oder mehrere zusätzliche Deployment-Lizenzen erwerben. Um Lizenzen und Upgrades zu erwerben, besuchen Sie den Blackfish SQL-Online-Shop auf der folgenden Website: http://shop.codegear.com. Weitere Ressourcen Nützliche technische Ressourcen sind: JDBC • JDBC™ API-Dokumentation unter java.sun.com • JDBC API Tutorial and Reference von Seth White et al; veröffentlicht bei Addison Wesley SQL • A Guide to The SQL Standard, by C. J. Date und Hugh Darwen; veröffentlicht bei Addison Wesley DataExpress-JavaBeans • DataExpress-Referenz der Komponentenbibliothek in der Hilfe zu Blackfish SQL für Java Siehe auch Übersicht ( see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( 2 see page 141) see page 137) see page 43) 2 Blackfish SQL 2 2 Übersicht In diesem Kapitel werden die Blackfish SQL-Funktionen beschrieben. • Blackfish SQL • Blackfish SQL-DataStore • Kompatibilität zwischen Windows und Java • Blackfish SQL für Java-Konnektivität • Blackfish SQL API für Windows • In SQL verfügbare Administrations- und Dienstprogrammfunktionen Blackfish SQL Blackfish™ SQL ist eine äußerst leistungsfähige, transaktionale Datenbank mit geringem Arbeitsspeicherverbrauch. Blackfish SQL wurde ursprünglich als eine vollständig in Java programmierte Datenbank mit Namen JDataStore implementiert. Heute heißt sie Blackfish SQL für Java. Blackfish SQL wurde anschließend von Java nach C# portiert. Die C#-Implementierung heißt Blackfish SQL für Windows. Das Design und die Implementierung von Blackfish SQL betonen die Datenbankleistung, die Skalierbarkeit, die einfache Verwendung und eine starke Einhaltung der Industriestandards. Blackfish SQL hat folgende Eigenschaften: • Kompatibilität mit Industriestandards. • Entry Level SQL-92 • Unicode-Speicherung von Zeichendaten • Unicode-basierende Sortierfolge für Sortierung und Indizierung • dbExpress 4-Treiber für Win32-Delphi und -C++ • ADO.NET 2.0-Provider für .NET • JDBC für Java • JavaBean-Datenzugriffskomponenten für Java • Verteilte XA/JTATransaktionen für Java • Hervorragende Performance und Skalierbarkeit für Anwendungen mit anspruchsvoller Online-Transaktionsverarbeitung (OLTP) und Entscheidungsunterstützung (DSS) • Gespeicherte Prozeduren und Trigger für Delphi, C# und VB.NET unter Windows 3 Blackfish SQL 2 • Gespeicherte Prozeduren und Trigger für Java • Keine Administration erforderlich; Deployment in Form eines einzigen Assemblies oder einer einzelnen Jar-Datei • Inkrementelles Datenbank-Backup und Failover in der Java-Version 2 Blackfish SQL-DataStore Blackfish SQL ist sowohl der Name des Produkts als auch der zugehörigen Tools und des Dateiformats. In RAD Studio gibt es Assemblies, die Klassen enthalten, die mit DataStore beginnen. Kompatibilität zwischen Windows und Java Blackfish SQL für Windows und Blackfish SQL für Java sind kompatibel miteinander, allerdings mit einigen Einschränkungen. Die Dateiformate der Datenbanken von Blackfish SQL für Windows und Blackfish SQL für Java sind binär-kompatibel. Darüber hinaus sind auch die Datenbank-Clients und -Server austauschbar. Windows-Clients können zu Java-Servern eine Verbindung herstellen, und Java-Clients zu Windows-Servern. Da die Blackfish SQL für Windows-Implementierung neuer als die für Java ist, werden einige der in Blackfish SQL für Java vorhandenen Funktionen in der Windows-Version noch nicht unterstützt. Weitere Informationen zur Blackfish SQL-Kompatibilität finden Sie unter Systemarchitektur. Blackfish SQL für Windows-Konnektivität Blackfish SQL für Windows stellt die folgenden Datenbanktreiber bereit: • DBXClient: Dieser 100% Object Pascal dbExpress 4-Datenbanktreiber ermöglicht Win32 Delphi- und C++-Anwendungen, remote eine Verbindung zu einem Blackfish SQL für Windows- oder Blackfish SQL für Java-Server herzustellen. • Lokaler ADO.NET 2.0-Provider: Dieser Treiber (100% managed code driver) ermöglicht es .NET-Anwendungen, eine Verbindung zu einem lokalen Blackfish SQL für Windows-Server herzustellen. Der lokale ADO.NET-Treiber wird im selben Prozess wie der BlackFish SQL-Datenbank-Kernel ausgeführt, um bessere Leistung zu erzielen. • Remote-ADO.NET 2.0-Provider: Dieser Treiber (100% managed code driver) ermöglicht es .NET-Anwendungen, eine Remote-Verbindung zu einem Blackfish SQL für Windows- oder Blackfish SQL für Java-Server herzustellen. Unter Verbindungen einrichten finden Sie Anweisungen für die Verwendung dieser Treiber. Blackfish SQL API für Windows Die Blackfish SQL API kann in Programmen, die mit Delphi oder C++ erstellt werden, mit dem DBXClient DBX4-Treiber verwendet werden. .NET-Anwendungen können die API mit dem ADO.NET-Provider verwenden. In RAD Studio befindet sich die API in den Namespaces Borland.Data.DataStore und Borland.Data.MetaData. Die unten aufgelisteten Administrationsfunktionen werden im Daten-Explorer für Blackfish SQL für Windows noch nicht unterstützt. Verwenden Sie SQL-Befehle oder in Blackfish SQL integrierte gespeicherte Prozeduren für DB_ADMIN, um diese Aufgaben auszuführen. • Erstellen bzw. Ändern der Spalteneigenschaften "autoincrement" und "max inline" • Erstellen sekundärer Indizes • Erstellen, Ändern und Entfernen von Benutzern und Rollen • Erstellen, Ändern und Entfernen von Datenbankspiegelungen • Datenbankverschlüsselung • Datenbank-Backup Für SQL verfügbare Administrations- und Dienstprogrammfunktionen Es stehen zwei Klassen zur Verfügung: DB_ADMIN und DB_UTIL. Diese Methoden können in SQL mithilfe der 4 2 Blackfish SQL CALL-Anweisung aufgerufen werden. Sie können ohne einen METHOD-Alias aufgerufen werden, da der Blackfish SQL-Dialekt Methoden in DB_ADMIN als integrierte Methoden erkennt. DB_ADMIN-Klasse DB_ADMIN ist eine Gruppe gespeicherter Prozeduren (Stored Procedures) zum Ausführen Datenbankadministrationsaufgaben. Folgende Funktionen stehen unter anderem zur Verfügung: einer Vielzahl von • Konfigurieren eines automatischen Failover und eines inkrementellen Backups • Anzeigen und Ändern von Datenbankkonfigurationen • Datenbank-Backups (explizit) • Datenbankverschlüsselung • Spiegelungsmanagement Weitere Informationen hierzu finden Sie unter Gespeicherte Prozeduren - Referenz. DB_UTIL-Klasse DB_UTIL besteht aus gespeicherten SQL-Prozeduren (SQL Stored Procedures) zum Ausführen numerischer, String- und Datum/Zeit-Operationen auf in Datenbanktabellen gespeicherten Daten. Zu diesen Prozeduren gehören folgende Funktionen: • Mathematische Funktionen, beispielsweise trigonometrische und arithmetische Funktionen sowie Funktionen zum Generieren von Zufallszahlen • Funktionen zur String-Manipulation • Datums- und Zeitfunktionen Weitere Informationen hierzu finden Sie unter Gespeicherte Prozeduren - Referenz. ADO.NET Blackfish SQL enthält eine ADO.NET-Implementierung. Diese entspricht dem AdoDbx-Client, der ebenfalls eine ADO.NET-Implementierung ist. • DataStoreCommand: Ermöglicht die Ausführung von SQL-Anweisungen und gespeicherter Prozeduren. • DataStoreCommandBuilder: Generiert Befehle für eine einzelne Tabelle zum Abgleich der an einem DataSet vorgenommenen Änderungen mit der zugrunde liegenden Datenbank. • DataStoreConnection: Ermöglicht eine Verbindung zu einer Datenbank. • DataStoreConnectionPool: Ermöglicht Zugriff auf einen Verbindungspool. • DataStoreDataAdapter: Füllt ein DataSet mit Werten und aktualisiert eine Datenbank. • DataStoreDataReader: Ermöglicht Zugriff auf eine Ergebnistabelle von einem Datenbank-Server. • DataStoreDataSourceEnumerator: Bietet einen Enumerator zum Suchen aller Datenquellen im lokalen Netzwerk. • DataStoreParameter: Gibt einen Parameter für DataStoreCommand an. • DataStoreParameterCollection: Zusammenstellung von Parametern für DataStoreCommand. • DataStoreProviderFactory: Basisklasse für die Provider-Implementierung von Datenquellklassen. • DataStoreRowUpdatedEventArgs: Enthält Daten für das RowUpdated-Ereignis von DataStoreDataAdapter. • DataStoreRowUpdatingEventArgs: Enthält Daten für das RowUpdating-Ereignis von DataStoreDataAdapter. • DataStoreTransaction: Ermöglicht eine Transaktion. Siehe auch Vorwort ( see page 1) Systemarchitektur ( see page 7) 5 2 Blackfish SQL Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( 2 Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( 6 2 see page 141) see page 137) see page 43) 3 Blackfish SQL 3 3 Systemarchitektur Dieses Kapitel enthält eine Übersicht der Blackfish SQL-Systemarchitektur. • Kompatibilität • Windows-Konnektivität • Java-Konnektivität • Unterschiede zwischen lokalen und Remote-Treibern • Datenbankdateien • Datenbankdateisystem • Transaktionsmanagement • Hohe Verfügbarkeit • Heterogene Replizierung mithilfe von DataExpress Blackfish SQL-Kompatibilität Blackfish SQL für Windows und Blackfish SQL für Java sind auf folgende Weise kompatibel: • Die Dateiformate der Datenbanken von Blackfish SQL für Windows und Blackfish SQL für Java sind binär-kompatibel. • Darüber hinaus sind auch die Datenbank-Clients und die -Server austauschbar. • Windows-Clients können zu Java-Servern eine Verbindung herstellen, und Java-Clients zu Windows-Servern. Die Kompatibilität ist auf folgende Weise eingeschränkt: • Der Objekt-Typ verwendet plattformspezifische Serialisierung. Aus diesem Grund können die Daten nicht zwischen zwei unterschiedlichen Clients ausgetauscht werden: • Ein ADO-Treiber kann kein Java-serialisiertes Objekt lesen. • Ein Java-Treiber kann kein .NET-serialisiertes Objekt lesen. • Ein DbxClient-Treiber kann keine Java- oder .NET-serialisierten Objekte lesen. • Die maximale Skalierung für einen Dezimalwert ist in Java und .NET unterschiedlich. • Bei Blackfish SQL für Java hat der Timestamp-Typ zwei Nachkommastellen mehr. Die folgenden Blackfish SQL für Java-Funktionen werden in der Windows-Version noch nicht unterstützt: • ISQL SQL Command Line Interpreter 7 Blackfish SQL 3 • Hochverfügbarkeitsfunktionen, einschließlich inkrementellem Backup und Failover • Grafisches Tool für administrative Funktionen • Zugriff auf Datei- und Objektdatenströme • Verfolgen und Auflösen von Einfüge-, Aktualisierungs- und Löschoperationen auf Zeilenebene • Zugriff auf das Blackfish SQL-Dateisystemverzeichnis Blackfish SQL für Windows-Konnektivität Windows-Anwendungen können eine oder mehrere der folgenden Konnektivitätslösungen verwenden, um programmtechnisch auf eine Blackfish SQL-Datenbank zuzugreifen: 3 • DBXClient DBXClient ist ein 100% Object Pascal dbExpress 4-Datenbanktreiber, der Win32 Delphi- und C++-Anwendungen ermöglicht, eine Verbindung zu einem Blackfish SQL für Windows- oder Blackfish SQL für Java-Server herzustellen. • ADO.NET ADO.NET ist der Microsoft-Standard für Datenbankkonnektivität auf der .NET-Plattform. Blackfish SQL für Windows hat die folgenden ADO.NET-Provider: • Lokaler ADO.NET 2.0-Provider: Dieser Treiber (100% managed code driver) ermöglicht es .NET-Anwendungen, eine Verbindung zu einem lokalen Blackfish SQL-Server herzustellen. Der lokale ADO.NET-Treiber wird im selben Prozess wie der BlackFish SQL-Datenbank-Kernel ausgeführt, um eine bessere Performance zu erzielen. • Remote-ADO.NET 2.0-Provider: Dieser Treiber (100% managed code driver) ermöglicht es .NET-Anwendungen, eine Remote-Verbindung zu einem Blackfish SQL für Windows- oder Blackfish SQL für Java-Server herzustellen. Unter Verbindungen einrichten finden Sie Anweisungen und Code-Beispiele für die Verwendung dieser Treiber. Blackfish SQL für Java-Konnektivität Java-Anwendungen können eine oder mehrere der folgenden Konnektivitätslösungen verwenden, um programmtechnisch auf eine Blackfish SQL-Datenbank zuzugreifen: • JDBC-Typ 4-Treiber JDBC ist eine dem Industriestandard entsprechende SQL-Call-Level-Schnittstelle für Java-Anwendungen. Blackfish SQL für Java stellt die folgenden JDBC-Treiber bereit: • Lokaler JDBC-Treiber: Dieser Treiber (100% managed code driver) ermöglicht es Java-Anwendungen, eine Verbindung zu einem lokalen Blackfish SQL-Server herzustellen. Der lokale JDBC-Treiber wird im selben Prozess wie der BlackFish SQL-Datenbank-Kernel ausgeführt, um eine bessere Performance zu erzielen. • Remote-JDBC-Treiber: Dieser Treiber (100% managed code driver) ermöglicht es Java-Anwendungen, eine Remote-Verbindung zu einem Blackfish SQL für Windows- oder Blackfish SQL für Java-Server herzustellen. • ODBC-zu-JDBC-Gateway ODBC-JDBC Gateway von EasySoft ist eine dem Industriestandard entsprechende SQL-Call-Level-Schnittstelle. Mithilfe des ODBC-JDBC-Gateways von EasySoft können native Anwendungen auf Blackfish SQL-Datenbanken zugreifen. • DataExpress-JavaBeans DataExpress-JavaBeans bieten eine zusätzliche Funktionalität, die vom JDBC-Standard nicht abgedeckt wird. Weitere Details hierzu finden Sie unter DataExpress JavaBeans. Unter Verbindungen einrichten finden Sie Anweisungen und Code-Beispiele für die Verwendung dieser Treiber. DataExpress-JavaBeans HINWEIS: Diese Funktion ist nur bei Blackfish SQL für Java verfügbar. DataExpress ist ein Satz von JavaBean-Laufzeitkomponenten, die eine zusätzliche Funktionalität bieten, die vom JDBC-Standard nicht abgedeckt wird. JavaBean ist eine dem Industriestandard entsprechende Komponentenarchitektur für Java. Der JavaBean-Standard legt viele wichtige Aspekte der für RAD-Entwicklungsumgebungen erforderlichen Komponenten fest. JavaBean-Komponenten können in einem visuellen Designer entwickelt und mit den Eigenschaften, Methoden und Ereignissen angepasst werden, die sie darstellen. DataExpress ist im Lieferumfang der Visual Designer-Komponentenpalette von CodeGear JBuilder enthalten. Weitere Informationen zur Verwendung von DataExpress aus JBuilder heraus finden Sie in der JBuilder-Hilfe. Da DataExpress ein Set von Laufzeitkomponenten ist, müssen Sie JBuilder nicht verwenden, um Anwendungen, die 8 3 Blackfish SQL DataExpress nutzen, zu entwickeln und zum Einsatz bereitzustellen. Die meisten der DataExpress-JavaBean-Komponenten sind für die Entwicklung server- und clientseitiger Datenbankanwendungen erforderlich. Clientseitige Anwendungen benötigen eine qualitativ hochwertige Datenbindung für visuelle Komponenten, z. B. grid controls, und erfordern außerdem die Unterstützung zum Lesen und Schreiben von Daten in einer Datenbank. Serverseitige Anwendungen benötigen Datenzugriffskomponenten, um das Lesen und Schreiben von Daten in einer Datenbank zu unterstützen. Die Präsentation wird in der Regel von einem Generierungssystem für Web-Seiten gehandhabt, z. B. Java Server Pages (JSPs). Obwohl DataExpress über eine umfangreiche Unterstützung für die clientseitige Datenbindung für visuelle Komponentenbibliotheken, z. B. dbSwing und JBCL, verfügt, trennt das DataExpress-Design die Präsentations- von der Datenzugriffsschicht. Dadurch können DataExpress-Komponenten als Datenzugriffsschicht für andere Präsentationsparadigmen verwendet werden, z. B. als JSP/Servlet-Ansatz der InternetBeans Express-Technologie von JBuilder. Die DataExpress-Architektur ermöglicht, dass eine optionale Speicherschnittstelle die von einer Datenquelle gelesenen Daten zwischenspeichert. Derzeit existieren nur zwei Implementierungen dieses Interfaces: MemoryStore (Vorgabe) und DataStore. Durch das Festlegen von nur zwei Eigenschaften für eine StorageDataSet-JavaBean-Komponente kann eine Blackfish SQL-Tabelle mit einem StorageDataSet-JavaBean direkt geöffnet und bearbeitet werden. Durch das Festlegen der DataSet-Eigenschaft für eine dbSwing-GridControl-Komponente kann der gesamte Inhalt großer Tabellen mit hoher Geschwindigkeit direkt durchsucht und bearbeitet werden. Dies bietet eine Datenzugriffsschicht auf ISAM-Ebene für Blackfish SQL-Tabellen. Administrative Funktionen mit DataExpress-JavaBeans automatisieren Es gibt viele DataExpress-Komponenten, die zur Automatisierung von administrativen Aufgaben verwendet werden können. Dazu gehören u. a. Folgende: Häufig verwendete Komponenten sind: Administrative DataExpress-Komponenten Aufgabe Komponente Benutzerdefiniertes Starten und Herunterfahren des com.borland.datastore.jdbc.DataStoreServer Servers: Sichern, Wiederherstellen Datenbanken: und Packen von com.borland.datastore.DataStoreConnection.copyStreams() Sicherheitsadministration: com.borland.datastore.DataStoreConnection Transaktionsmanagement com.borland.datastore.TxManager com.borland.datastore.DataStore DataExpress-JavaBean-Quelltext JBuilder bietet eine jar-Quelltextdatei, die viele der DataExpress-JavaBean-Komponenten enthält. Dadurch können Sie Ihre Anwendungen einfacher debuggen und haben ein besseres Verständnis der DataExpress-JavaBean-Komponenten. Unterschiede zwischen lokalen und Remote-Treibern Der Hauptunterschied zwischen lokalen und Remote-Treibern mit Blackfish SQL besteht hierin: • Lokaler Treiber: Die Blackfish SQL-Datenbank-Engine wird im selben Prozess ausgeführt wie die Anwendung. • Remote-Treiber: Die Blackfish SQL-Datenbank-Engine wird entweder im selben Prozess wie die Anwendung oder in einem anderen Prozess ausgeführt. Vorteile der Verwendung eines lokalen Treibers gegenüber dem Zugriff auf eine Datenbank Ein lokaler Blackfish SQL-Treiber bietet folgende Vorteile: 9 3 Blackfish SQL 3 • Schnelle Schnittstelle zur Datenbank Treiberaufrufe werden direkt im Datenbankkernel auf dem gleichen Aufruf-Stack durchgeführt. Es gibt keine Remote-Prozeduraufrufe ("remote procedure calls") an Datenbank-Server, die in einem anderen Prozess ausgeführt werden. • Problemlos in eine Anwendung einzubetten Der Datenbank-Server muss nicht neu konfiguriert oder gestartet werden. Der ausführbare Code für den Datenbankkernel, den Datenbanktreiber und die Anwendung werden im gleichen Prozess ausgeführt. Vorteile der Verwendung eines Remote-Treibers gegenüber dem Zugriff auf eine Datenbank 3 Sie können den externen Blackfish SQL-JDBC-Treiber verwenden, um Blackfish SQL in einem separaten Datenbankserver-Prozess auszuführen. Damit die Anwendung den Remote-JDBC-Treiber verwenden kann, muss vorher der Blackfish SQL-Server-Prozess gestartet werden. Das Ausführen des Blackfish SQL-Datenbank-Kernels in einem separaten Datenbank-Server-Prozess bietet folgende Vorteile: • Multiprozess-Zugriff auf eine Datenbank. Wenn mehrere Prozesse auf einem oder mehreren Computern auf eine einzige Blackfish SQL-Datenbank zugreifen müssen, müssen ein Blackfish SQL-Server gestartet und die externen Treiber von der Anwendung verwendet werden. • Verbesserte Leistung mithilfe mehrerer Computer Wenn der Anwendungs- oder Web-Server einen großen Anteil des Arbeitsspeichers oder der CPU-Ressourcen in Anspruch nimmt, können Sie in der Regel eine bessere Leistung erzielen, wenn Sie den Blackfish SQL-Server auf einem separaten Computer ausführen. • Verbesserte Fehlertoleranz. Anwendungen, die eine Remote-Verbindung verwenden, laufen in der Regel in einem separaten Prozess. Fehlerhafte Anwendungen können beendet werden, ohne dass der Datenbank-Server geschlossen werden muss. Vorteile der Verwendung lokaler Treiber und Remote-Treiber für den Zugriff auf eine Datenbank Es ist gelegentlich von Vorteil, den lokalen und den externen Treiber für den Zugriff auf dieselbe Datenbank zu verwenden. Eine Blackfish SQL-Datenbankdatei kann nur von einem Betriebssystem-Prozess offen gehalten werden. Wenn Sie eine Verbindung mithilfe des lokalen Treibers herstellen, hält der Prozess, der den lokalen Treiber verwendet, die Datenbankdatei geöffnet. Wenn die Verbindung über den externen Treiber hergestellt wird, hält der Blackfish SQL-Server-Prozess die Datenbankdatei geöffnet. Da der lokale Treiber die Datenbankdatei im selben Prozess geöffnet hält, verhindert er Verbindungen vom externen Treiber. Wenn jedoch der Prozess, der den lokalen Treiber verwendet, im selben Prozess auch einen Blackfish SQL-Server startet, können andere Prozesse, die den externen Treiber verwenden, auf dieselbe Datenbank wie der lokale Treiber zugreifen. Der Blackfish SQL-Server kann in einer Anwendung gestartet werden, indem Sie eine einzelne Java-Codezeile verwenden, die eine DataStoreServer-Komponente instantiiert und ihre start-Methode ausführt. DataStoreServer wird auf einem separaten Thread ausgeführt und verarbeitet Verbindungsanforderungen von Prozessen, die den externen Treiber für den Zugriff auf eine Blackfish SQL-Datenbank auf dem Computer verwenden, auf dem DataStoreServer gestartet wurde. Zudem kann der lokale Treiber von der Anwendung, die DataStoreServer gestartet hat, für schnellere prozessinterne Aufrufe in die Blackfish SQL-Datenbank-Engine verwendet werden. Blackfish SQL-Datenbankdateien Diese Dateien werden durch Blackfish SQL erstellt und verwendet: • Dateiname.jds: Eine einzelne Datei als Ablageort aller Datenbankobjekte. • Datenbankname_LOGA_*: Transaktionale Protokolldateien. Wenn die Datenbankdatei verschoben wird. müssen die Protokolldateien zusammen mit ihr verschoben werden. • Datenbankname_LOGA_ANCHOR: Speichert Konfigurationsinformationen für Protokolldateien redundant. • Datenbankname_STATUS*: Protokolldateien werden erstellt, wenn die Statusprotokollierung für die Datenbank aktiviert ist. Eine Blackfish SQL-Datenbank kann auch dann noch verwendet werden, wenn die Anker- oder Statusprotokolldateien nicht 10 3 Blackfish SQL existieren. Eine nichttransaktionale (schreibgeschützte) Datenbank benötigt nur die .jds-Datenbankdatei. Die Spezifikationen für die Blackfish SQL-Datenbankdateikapazität sind: Kapazität der Blackfish SQL-Datenbankdatei Spezifikation Wert Minimale Blockgröße: 1 KB Maximale Blockgröße: 32 KB Standardblockgröße 4 KB Maximale Größe SQL-Datenbankdatei einer 3 Blackfish 2 Milliarden Blöcke. Bei der Standardblockgröße ergibt dies ein Maximum von 8.796.093.022.208 Byte (8 TB). Maximale Anzahl Zeilen pro Tabellenstrom 281,474,976,710,656 Maximale Zeilenlänge 1/3 der Blockgröße. Long Strings, Objekte und Eingabeströme, die als Blobs gespeichert werden, damit sie keinen Speicherplatz in der Zeile belegen. Maximale BLOB-Größe 2 GB pro BLOB Maximale Dateistromgröße 2 GB pro BLOB Blackfish SQL-Datenbankdateisystem Eine Blackfish SQL-Datenbank kann die folgenden Typen von Datenströmen enthalten: • Tabellenströme: Hierbei handelt es sich um Datenbanktabellen, die in der Regel mit SQL erstellt wurden. Ein Tabellenstrom kann über verknüpfte sekundäre Indizes und Blob-Speicher verfügen. • Dateiströme: Es gibt zwei Typen von Dateiströmen: • Beliebige, mit DataStoreConnection.createFileStream() erzeugte Dateien • Serialisierte Java-Objekte werden als Dateiströme gespeichert Eine einzelne Blackfish SQL-Datenbank kann alle Datenstromtypen enthalten. Datenströme sind in einem Dateisystemverzeichnis organisiert. Durch die Fähigkeit, beide Tabellen und beliebige Dateien im selben Dateisystem zu speichern, können alle Daten einer Anwendung in einem einzelnen portierbaren, transaktionalen Dateisystem gespeichert werden. Eine Blackfish SQL-Datenbank kann außerdem verschlüsselt und durch ein Passwort geschützt werden. Die Spezifikationen für die Blackfish SQL-Datenbankdateisysteme sind: Spezifikation des Blackfish SQL-Datenbankdateisystems Spezifikation Wert Verzeichnistrennzeichen für Datenströme / Maximale Länge Datenstromnamens des 192 Byte • Günstigster Fall (bei 8-Bit-Zeichensätzen): 192 Zeichen • Ungünstigster Fall (bei Doppel-Byte-Zeichensätzen): 95 Zeichen (ein Byte geht für die DBCS-Kennzeichnung verloren) 11 Blackfish SQL Reservierte Namen 3 Datenstromnamen, die mit SYS beginnen, sind reserviert. Blackfish SQL verfügt über folgende Systemtabellen: • SYS/Connections • SYS/Queries • SYS/Users 3 Spezifische Datenströme für Blackfish SQL für Java Auf einige Tabellenströme und alle Dateiströme kann derzeit nur von Java-Anwendungen aus zugegriffen werden. Wenn die resolvable-Eigenschaft der Tabelle festgelegt ist, werden außerdem alle Einfüge-, Aktualisierungs- und Löschoperationen an der Tabelle protokolliert. Mithilfe dieser Funktion können DataExpress-Komponenten Änderungen aus einer replizierten Tabelle mit der Datenbank synchronisieren, aus der die Tabelle repliziert wurde. Dateiströme sind Random-Access-Dateien. Dateiströme können in zwei verschiedene Kategorien aufgeteilt werden: • Beliebige, mit DataStoreConnection.createFileStream() erzeugte Dateien: In Ströme dieses Typs kann geschrieben, sie können durchsucht und gelesen werden. • Serialisierte Java-Objekte werden als Dateiströme gespeichert: In Ströme dieses Typs kann geschrieben, sie können durchsucht und gelesen werden. Der Name, auf den in der API als storeName Bezug genommen wird und bei dem die Groß-/Kleinschreibung berücksichtigt wird, bestimmt den Namen des Datenstroms. Der Name kann bis zu 192 Byte lang sein. Im internen Verzeichnis der Blackfish SQL-Datenbank wird dieser Name zusammen mit weiteren Informationen über den Datenstrom gespeichert. Im Datenstromnamen werden Schrägstriche (/) als Trennzeichen zwischen Verzeichnisnamen verwendet, um eine hierarchische Gliederung der Verzeichnisse zu ermöglichen. JdsExplorer verwendet diese Struktur, um den Inhalt des Verzeichnisses in einer Baumstruktur anzuzeigen. Vorteile der Verwendung des Blackfish SQL-Dateisystems Bei der beständigen Speicherung beliebiger Dateien bietet das Blackfish SQL-Dateisystem mehrere Vorteile gegenüber der Verwendung der im java.io-Package enthaltenen JDK-Klassen: • Es ist leichter, da nur eine statt vier Klassen erforderlich ist (FileOutputStream, ObjectOutputStream, FileInputStream, ObjectInputStream). • Sie können alle Anwendungsdateien und -objekte in einer einzigen Datei zusammenfassen und problemlos jederzeit über einen logischen Namen auf sie zugreifen, anstatt ein "Streaming" aller Objekte in eine Datei vorzunehmen. • Darüber hinaus wird aufgrund der Art der Cluster-Zuweisung einiger Betriebssysteme weniger Speicherplatz benötigt. Die Standard-Blockgröße in einer Blackfish SQL-Datenbankdatei ist klein (4 KB). • Da Sie nicht vom jeweiligen Dateisystem abhängig sind, ist die Anwendung besser portierbar. So sind beispielsweise je nach Betriebssystem bestimmte Zeichen in Dateinamen zulässig, andere wiederum nicht. Bei einigen Systemen wird zwischen Groß- und Kleinschreibung unterschieden, bei anderen nicht. Die Regeln für die Namensgebung sind innerhalb des Blackfish SQL-Dateisystems jedoch für alle Plattformen gleich. • Blackfish SQL bietet ein transaktionales Dateisystem, das zudem verschlüsselt und mit einem Passwort geschützt werden kann. Blackfish SQL-Verzeichnisinhalt Hinweis: Derzeit kann auf das Verzeichnis für die Blackfish SQL-Datenbank nur aus Java-Anwendungen zugegriffen werden. Erfreulicherweise brauchen die meisten Anwendungen nicht direkt auf das Verzeichnis zugreifen. 12 3 Blackfish SQL Der JdsExplorer-Baum bietet eine hierarchische Ansicht des Blackfish SQL-Verzeichnisses. Das Blackfish SQL-Verzeichnis kann auch programmtechnisch mit einer DataExpress-StorageDataSet-Komponente geöffnet werden. Dabei wird eine tabularische Ansicht aller im Blackfish SQL-Dateisystem gespeicherten Datenströme bereitgestellt. Die Verzeichnistabelle hat die folgende Struktur: Spalten der Blackfish SQL-Verzeichnistabelle # Name Konstante Typ Inhalt 1 State DIR_STATE short Ob der Datenstrom aktiv oder gelöscht ist 2 DeleteTime DIR_DEL_TIME long Wenn gelöscht: Zeitpunkt; sonst Null 3 StoreName DIR_STORE_NAME String Der Name des Datenspeichers 4 Type DIR_TYPE short Bit-Felder zur Angabe der Datenstromtypen 5 Id DIR_ID int Eine eindeutige Kennzahl 6 Properties DIR_PROPERTIES String Eigenschaften und Ereignisse zu einem DataSet-Datenstrom 7 ModTime DIR_MOD_TIME long Zeitpunkt der letzten Änderung des Datenstroms 8 Length DIR_LENGTH long Länge des Datenstroms in Byte 9 BlobLength DIR_BLOB_LENGTH long Länge der BLOBs in der Tabellen-Datenstrom in Byte 3 Auf die Spalten kann über den Namen oder die Nummer zugegriffen werden. Für alle Spaltennamen sind Konstanten als DataStore-Klassenvariablen definiert. Die beste Methode, diese Spalten zu referenzieren, besteht darin, diese Konstanten zu verwenden. Die Konstanten ermöglichen eine Überprüfung zum Zeitpunkt der Compilierung und stellen sicher, dass die referenzierte Spalte validiert wird. Für die verschiedenen Werte der State-Spalte gibt es Konstanten, deren Namen auf _STATE enden. Darüber hinaus existieren Konstanten für die verschiedenen Werte und Bit-Masken der Spalte Type, deren Namen auf _STREAM enden. Weitere Informationen zur DataStore-Klasse und eine Liste dieser Konstanten finden Sie in der Online-Hilfe. Einige Besonderheiten von Datenströmen Zeitangaben im Blackfish SQL-Verzeichnis erfolgen im UTC-Format (Coordinated Universal Time). Wie bei vielen Dateisystemen führt das Löschen eines Stroms in Blackfish SQL dazu, dass der von ihm belegte Platz als verfügbar gekennzeichnet wird, während jedoch der vermeintlich gelöschte Inhalt und der auf diesen Platz verweisende Verzeichniseintrag weiterhin vorhanden sind. Das bedeutet, dass Sie einen gelöschten Datenstrom wiederherstellen können, wenn er noch nicht überschrieben wurde. Weitere Informationen zum Löschen und Wiederherstellen von Datenströmen finden Sie unter "Datenströme löschen," "Wie Blackfish SQL gelöschte Blöcke wiederverwendet" und "Datenstöme wiederherstellen". Type gibt an, ob es sich bei einem Datenstrom um eine Datei oder einen Tabellenstrom handelt; allerdings existieren noch zahlreiche interne, untergeordnete Typen von Tabellenströmen (für Indizes, Aggregate und dergleichen). Diese internen Datenströme sind mit dem HIDDEN_STREAM-Bit gekennzeichnet, welches bewirkt, dass diese Datenströme nicht angezeigt werden. Wenn Sie das Verzeichnis lesen, können Sie festlegen, ob diese Ströme angezeigt oder verborgen werden sollen. Diese internen Datenströme besitzen denselben StoreName wie der Tabellenstrom, mit dem sie verknüpft sind. Das heißt, dass der StoreName allein nicht immer eindeutig einen Datenstrom identifiziert. Einige interne Datenstromtypen können mehrere Instanzen haben. Die ID für jeden Datenstrom ist immer eindeutig. Der StoreName ist jedoch eindeutig genug für den storeName-Parameter, der auf API-Ebene verwendet wird. Wenn Sie beispielsweise einen Tabellenstrom löschen, werden alle Datenströme mit diesem storeName gelöscht. Sortierfolgen bei Verzeichnissen Die Verzeichnistabelle wird nach den ersten fünf Spalten sortiert. Aufgrund der in der Spalte Status gespeicherten Werte werden zuerst alle aktiven Datenströme in alphabetischer Reihenfolge nach dem Namen aufgelistet. Dann folgen alle gelöschten 13 Blackfish SQL 3 Datenströme in der Reihenfolge ihres Löschzeitpunkts (vom ältesten zum neuesten. HINWEIS: Sie können die DataSetView-Komponente nicht verwenden, um eine andere Sortierfolge zu erstellen. Speicherreservierung bei Blackfish SQL-Dateisystemen Der Datenbankinhalt wird in einer einzelnen Datei gespeichert. Wenn die Transaktionsunterstützung für die Datenbank aktiviert ist, sind zusätzliche Dateien für Transaktionsprotokolle vorhanden. Eine Datenbankdatei hat eine Standard-Blockgröße von 4096 Byte. Die Blockgröße der Datenbank ist die Größe, die für neue Zuordnungen in der Datenbank verwendet wird. Diese Größe legt außerdem die maximale Speichergröße einer Blackfish SQL-Datenbank fest. Die Formel für die Berechnung der maximalen Größe für Datenbankdateien lautet: <Byte-pro-Block> * 2^31 Für eine Blockgröße von 4096 Byte lautet der Wert ca. 8,8 Terabyte. 3 Wenn aus einer Blackfish SQL-Datenbankdatei Daten gelöscht oder entfernt werden, reduziert dies nicht automatisch ihre Größe. Neue Zuordnungen verwenden jedoch den Speicherplatz der gelöschten Zuordnungen. Gelöschter Speicherplatz im Dateisystem wird neuen Zuordnungen auf folgende Weise zur Verfügung gestellt: • Gelöschte Blöcke In diesem Fall wird ein gesamter Block aus der Liste der gelöschten Blöcke neu zugeordnet. • Teilweise gefüllte Blöcke In diesem Fall kann der freie Speicherplatz nur pro Datenstrom-Basis wiederverwendet werden. Insbesondere kann der freie Platz in Tabelle A nur durch eine neue Zuweisung für eine Zeile in Tabelle A wiederverwendet werden. Aus der Zuweisungsperspektive sind alle Tabellen, sekundäre Indizes, Blobs und Dateien separate Datenströme. Teilweise zugeordnete Blöcke sind im Schnitt zu mindestens 50 Prozent ausgelastet. Das Dateisystem stellt sicher, dass dies für alle Datenstromtypen im Blackfish SQL-Dateisystem gilt. Die einzige Ausnahme zu dieser Regel bildet ein Datenstrom, dem nur wenige Blöcke zugeordnet sind. Eine Blackfish SQL-Datenbankdatei kann komprimiert werden, um den gelöschten Speicherplatz zu entfernen und um das Dateisystem zu defragmentieren, sodass die Blöcke für jeden Datenstrom sich in aneinandergrenzenden Bereichen befinden. Um eine Datenbank mit JdsExplorer zu komprimieren, wählen Sie Tools > Packen. Sie können dies programmtechnisch bewerkstelligen, indem Sie die Methoden DB_ADMIN.COPY_USERS und DB_ADMIN.COPY_STREAMS verwenden. Datenströme löschen Beim Löschen eines Datenstroms wird sein Inhalt nicht wirklich überschrieben oder entfernt. Wie bei vielen Dateisystemen wird der vom gelöschten Datenstrom belegte Platz als verfügbar gekennzeichnet, und der auf diesen Platz verweisende Verzeichniseintrag wird als gelöscht gekennzeichnet. Die Zeit, zu der der Datenstrom gelöscht wurde, wird im Verzeichnis gespeichert. Über kurz oder lang wird der ursprünglich vom gelöschten Datenstrom belegte Platz mit Inhalten neuer Datenströme überschrieben, was dazu führt, dass der Inhalt des gelöschten Datenstroms endgültig nicht mehr wiederhergestellt werden kann. Sie können JdsExplorer verwenden, um Datenströme zu löschen, oder Sie können sie im Rahmen der Programmierung mithilfe der DataStoreConnection.deleteStream()-Methode löschen, an die der Name des zu löschenden Datenstroms als Argument übergeben wird. Wie Blackfish SQL gelöschte Blöcke wiederverwendet Blöcke einer Blackfish SQL-Datenbankdatei, die ursprünglich von gelöschten Datenströmen belegt waren, können gemäß der folgenden Regeln wieder in Anspruch genommen werden: • Blackfish SQL gibt immer erst gelöschten Speicherplatz frei, bevor er den Blöcken neuen Festplattenspeicher zuordnet. • Wenn es sich um eine transaktionale JDataStore-Datenbank handelt, muss die Transaktion, die den Datenstrom gelöscht hat, ausgeführt und bestätigt (commit) sein, bevor der verwendete Platz wieder zur Verfügung steht. • Diejenigen Datenströme, deren Löschzeitpunkte am weitesten zurückliegen, werden zuerst wieder für andere Prozesse freigegeben. • Bei Tabellenströmen werden zuerst wieder die Hilfsdatenströme (etwa für Indizes oder Aggregate) freigegeben. 14 3 Blackfish SQL • Speicherplatz wird beginnend vom Anfang des Datenstroms in Richtung Ende des Datenstroms für andere Speicherungsprozesse freigegeben. Dies bedeutet, dass Sie das Ende einer Datei oder Tabelle mit größerer Wahrscheinlichkeit wiederherstellen können als den Anfang. • Aufgrund des Verfahrens, mit dem Tabellendaten in Blöcken gespeichert werden, können die Zeilen eines Tabellenstroms niemals teilweise, sondern immer nur vollständig gelöscht bzw. wiederhergestellt werden. • Nachdem der gesamte Speicherplatz eines Datenstroms wieder neu belegt wurde, wird der Verzeichniseintrag zum betreffenden Datenstrom automatisch gelöscht (in diesem Fall besteht ohnehin keine Aussicht mehr auf Wiederherstellung der Daten). 3 Datenströme wiederherstellen Blackfish SQL erlaubt das Wiederherstellen gelöschter Datenströme, wenn ihr Speicherplatz nicht durch neue Speicherzuweisungen, wie im vorherigen Abschnitt beschrieben, verwendet wird. Sie können einen Datenstrom entweder mithilfe des JdsExplorer oder durch Aufruf der DataStoreConnection.undeleteStream()-Methode wiederherstellen. Da Tabellenströme aus mehreren Datenströmen des gleichen Namens bestehen, genügt der Datenstromname alleine nicht als Parameter, um das Löschen des Datenstroms im Rahmen der Programmierung rückgängig machen zu können. Vielmehr muss eine Zeile aus dem Blackfish SQL-Verzeichnis angegeben werden. Die Zeile enthält genügend Informationen, um einen bestimmten Datenstrom eindeutig identifizieren zu können. Die Methode DataStoreConnection.undeleteStream() verwendet eine solche Zeile als Parameter. Sie können damit das Verzeichnis-DataSet selbst übergeben. Die aktuelle Zeile im Verzeichnis-DataSet ist also die Zeile, die wiederhergestellt werden soll. Wenn Sie einen neuen Datenstrom mit dem Namen eines gelöschten Datenstrom erstellen, können Sie diesen Datenstrom nicht wiederherstellen, da sein Name von einem aktiven Datenstrom verwendet wird. Transaktionsmanagement Der Lebenszyklus einer Transaktion beginnt mit einer beliebigen Lese- oder Schreiboperation über eine Verbindung. Mithilfe von Datenstromsperrungen kontrolliert Blackfish SQL den Zugriff auf die Ressourcen. Damit Sie einen Datenstrom lesen oder ändern können (z. B. ein Byte in einer Datei oder eine Zeile in einer Tabelle), müssen Sie den Datenstrom sperren können. Wenn eine Verbindung eine Sperre hergestellt hat, bleibt diese bis zur Bestätigung (commit) oder zum Rückgängigmachen (rollback) der Transaktion erhalten. Anwendungen mit einer einzigen Verbindung ermöglichen Transaktionen hauptsächlich das Rückgängigmachen von Änderungen und die Implementierung einer Crash Recovery. Sie hätten aber auch eine Blackfish SQL-Datenbank transaktional machen können, sodass über JDBC darauf zugegriffen werden kann. Wenn Sie unter Verwendung von DataExpress auf diese Blackfish SQL-Datenbank zugreifen möchten, müssen Sie sich nun mit Transaktionen beschäftigen. Isolationsebenen für Transaktionen Blackfish SQL unterstützt alle vier durch die Standards ANSI/ISO SQL (SQL/92) festgelegten Isolationsebenen. Die serialisierbare Isolationsebene ermöglicht vollständige Transaktionsisolation. Eine Anwendung kann eine schwächere Isolationsebene wählen, um die Leistung zu verbessern oder um Deadlocks zu vermeiden. Bei geringerer Isolation können eine oder mehrere der folgenden Isolationsverletzungen auftreten: • Dirty Reads Operationen, bei denen eine Verbindung Daten lesen darf, die eine andere Verbindung geschrieben hat, die aber noch nicht bestätigt sind. • Nicht wiederholbare Leseoperationen Operationen, bei denen eine Verbindung eine bestätigte Zeile liest, eine andere Verbindung die betreffende Zeile ändert und bestätigt, die erste Verbindung die Zeile erneut liest und einen anderen (nämlich den geänderten, aktuellen) Wert erhält als bei der ersten Leseoperation. • Phantom-Leseoperationen Operationen, bei denen eine Verbindung alle Zeilen liest, die eine WHERE -Bedingung erfüllen, eine zweite Verbindung eine neue Zeile hinzufügt, die dann ebenfalls diese Bedingung erfüllt, und die erste Verbindung beim zweiten Lesen die ursprünglich nicht vorhandene, neue Zeile sieht. 15 Blackfish SQL 3 SQL92 legt vier Isolationsebenen hinsichtlich des Verhaltens fest, das eine Transaktion auf der jeweiligen Isolationsebene aufweisen darf. Es handelt sich dabei um die folgenden: Definitionen der SQL-Isolationsebenen 3 Isolationsebene Dirty Read Nonrepeatable Read Phantom Read Read uncommitted Möglich Möglich Möglich Read committed Nicht möglich Möglich Möglich Repeatable Read Nicht möglich Nicht möglich Möglich Serializable Nicht möglich Nicht möglich Nicht möglich Eine Isolationsebene für eine Blackfish SQL-Verbindung auswählen Die Richtlinien zur Auswahl einer Isolationsebene für eine Verbindung umfassen: Richtlinien für die Isolationsebene Isolationsebene Beschreibung Read Uncommitted Die Isolationsebene eignet sich für Berichte bei Ein-Benutzer-Programmen, bei denen inkonsistente Ansichten der Daten bei Transaktionen keine Rolle spielen. Diese Ebene ist insbesondere nützlich beim Durchsuchen von Blackfish SQL-Tabellen mit dbswing- und DataExpress-DataSet-Komponenten. Bei dieser Isolationsebene tritt ein minimaler Sperr-Overhead auf. Read Committed Diese Isolationsebene wird häufig für Hochleistungsanwendungen verwendet. Diese Ebene ist ideal für Datenzugriffsmodelle, die eine optimistische Concurrency-Steuerung verwenden. Bei diesen Datenzugriffsmodellen werden Lesevorgänge weitgehend zuerst ausgeführt. In einigen Fällen werden Lesevorgänge eigentlich als eigene, von den Schreibvorgängen getrennte Transaktion durchgeführt. Repeatable Read Diese Isolationsebene bietet höheren Schutz für konsistenten Datenzugriff bei Transaktionen ohne die verminderte Concurrency von TRANSACTION_SERIALIZABLE. Hier tritt jedoch ein erhöhter Sperr-Overhead auf, da Zeilensperrungen angefordert und für die Dauer der Transaktion aufrechterhalten werden müssen. Serializable Die Isolationsebene bietet eine vollständige Serialisierung der Transaktionen, hat aber eingeschränkte Concurrency und ein erhöhtes Deadlock-Risiko zur Folge. Obwohl bei dieser Isolationsebene nach wie vor Zeilensperrungen für übliche Vorgänge verwendet werden können, können manche Vorgänge dazu führen, dass der Sperr-Manager von Blackfish SQL häufiger Tabellensperrungen verwendet. Sperrvorgänge bei Blackfish SQL Die vom Blackfish SQL Lock Manager verwendeten Sperren sind: Blackfish SQL-Sperren Sperrung Beschreibung Sperrungen für kritische Diese internen Sperrungen werden verwendet, um interne Datenstrukturen zu schützen. Die Abschnitte Sperrungen für kritische Abschnitte werden normalerweise nur für einen kurzen Zeitraum aufrechterhalten. Sie werden unabhängig davon, wann die Transaktion bestätigt wird, angefordert und aufgehoben. Zeilensperrungen 16 Mit einer Zeilensperrung wird eine Zeile in einer Tabelle gesperrt. Diese Sperrung unterstützt Modi für gemeinsame und exklusive Sperrungen. Diese Zeilensperrungen werden aufgehoben, wenn die Transaktion bestätigt wird. 3 Blackfish SQL Tabellensperrungen Tabellensperrungen werden zum Sperren einer ganzen Tabelle verwendet. Diese Sperrung unterstützt Modi für gemeinsame und exklusive Sperrungen. Tabellensperren werden aufgehoben, wenn die Transaktion bestätigt wird. DDL-Tabellensperrungen DDL-Tabellensperrungen sind Sperren, die angelegt werden, wenn Datenbank-Metadaten erstellt, geändert oder entfernt werden. Diese Sperrung unterstützt Modi für gemeinsame und exklusive Sperrungen. • Gemeinsame DDL-Sperren werden von Transaktionen aufrechterhalten, bei denen Tabellen geöffnet sind. Gemeinsame DDL-Sperren werden erst aufgehoben, wenn zum einen die Transaktion bestätigt wird und zum anderen die Verbindung die Tabelle und alle Anweisungen schließt, die auf die Tabelle verweisen. 3 • Exklusive DDL-Sperren werden verwendet, wenn eine Tabelle gelöscht oder in ihrer Struktur verändert werden muss. Sie werden aufgehoben, wenn eine Transaktion durchgeführt wird. Sperrverhalten mit Blackfish SQL steuern Sie können Verbindungseigenschaften unter Beachtung der Groß- und Kleinschreibung angeben, um das Sperrverhalten zu steuern. Es gibt folgende Eigenschaftsnamen: Verbindungseigenschaften unter Beachtung der Groß- und Kleinschreibung zur Steuerung des Sperrverhaltens Eigenschaft Verhalten tableLockTables Gibt die Tabellen an, bei denen die Zeilensperrung deaktiviert werden soll. Dabei kann es sich um eine Liste von Tabellen handeln, die als ein String von durch Semikolon getrennten Tabellennamen unter Beachtung der Groß- und Kleinschreibung definiert ist. Setzen Sie diese Eigenschaft auf “*”. maxRowLocks Gibt die maximale Anzahl an Zeilensperrungen pro Tabelle an, die eine Transaktion anfordern darf, bevor eine Tabellensperrung aktiviert wird. Der Vorgabewert ist 50. lockWaitTime Gibt die maximale Anzahl an Millisekunden an, nach der eine Sperrung von einer anderen Transaktion aufgehoben werden kann. Wenn dieser Zeitraum überschritten wird, wird eine entsprechende Exception ausgelöst. readOnlyTxDelay Gibt die maximale Anzahl an Millisekunden an, nach der eine neue schreibgeschützte Ansicht der Datenbank gestartet wird. Details finden Sie in der Diskussion zu schreibgeschützten Transaktionen in Die Leistungsfähigkeit der Concurrency-Steuerung von Blackfish SQL verbessern. Sperr- und Isolationsebenen bei Blackfish SQL Die Verwendung von Tabellen- und Zeilensperrungen hängt von den verschiedenen Isolationsebenen ab. Die Verbindungseigenschaft tableLockTables deaktiviert die Zeilensperrung und wirkt sich auf alle Isolationsebenen aus. Sperren für kritische Abschnitte und DDL-Sperren werden in derselben Weise bei allen Isolationsebenen verwendet. Alle Isolationsebenen fordern mindestens eine exklusive Zeilensperrung für das Aktualisieren, Löschen und Einfügen von Zeilen an. Bei manchen Sperr-Eskalations-Szenarien kann stattdessen eine exklusive Tabellensperrung verwendet werden. In der folgenden Tabelle wird das Zeilensperrverhalten der Isolationsebenen für Blackfish SQL-Verbindungen beschrieben: Verwendung von Sperren und Isolationsebenen 17 Blackfish SQL 3 Isolationsebene Verhalten der Zeilensperrung für die Verbindung Read Uncommitted Auf dieser Ebene werden keine Zeilensperrungen für Lesevorgänge angefordert. Außerdem werden exklusive Zeilensperrungen nicht berücksichtigt, die von anderen Verbindungen nach dem Einfügen oder Aktualisieren einer Zeile aufrechterhalten werden. Read Committed Auf dieser Ebene werden keine Zeilensperrungen für Lesevorgänge angefordert. Eine Transaktion, die diese Isolationsebene verwendet, wird beim Lesen einer Zeile blockiert, für die eine andere Transaktion eine exklusive Zeilensperrung wegen eines Einfüge- oder Aktualisierungsvorgangs aufrechterhält. Diese Blockierung wird aufgehoben, wenn eine der folgenden Situationen eintritt: wenn die Schreibtransaktion bestätigt wird, wenn ein Deadlock erkannt wird oder wenn das lockTimeOut-Zeitlimit überschritten wird. 3 Repeatable Read Auf dieser Ebene werden gemeinsame Zeilensperrungen für Lesevorgänge angefordert. Serializable Diese Ebene fordert gemeinsame Zeilensperrungen für Abfragen an, die eine Zeile anhand eindeutiger Spaltenwerte (z. B. einem Primärschlüssel oder der Spalte INTERNALROW) auswählen. In SQL legt die WHERE-Klausel fest, ob eindeutige Spaltenwerte ausgewählt werden oder nicht. Exklusive Zeilensperrungen werden außerdem für Einfügungen, Aktualisierungen und Löschvorgänge von Zeilen verwendet, die durch eindeutige Spaltenwerte ermittelt werden. Die folgenden Operationen führen dazu, dass eine gemeinsame Tabellensperrung verwendet wird: • Lesevorgänge, bei denen Zeilen nicht auf der Grundlage eindeutiger Spaltenwerte ausgewählt werden. • Lesevorgänge, die keine Zeilen finden • Einfügungen und Aktualisierungen von nicht eindeutig angegebenen Zeilen Die Erweiterung von Zeilensperrungen zu Tabellensperrungen tritt in bestimmten Situationen bei Serializable ein (wie weiter oben beschrieben). Sie tritt aber auch bei allen Isolationsebenen ein, wenn der Wert der Eigenschaft maxRowLocks überschritten wird. Änderungen der Steuerung der gleichzeitigen Benutzung Blackfish SQL-Datenbankdateien, die mit älteren Versionen von Blackfish SQL erstellt wurden, verwenden auch weiterhin Tabellensperrungen zur Concurrency-Steuerung. Es gibt jedoch kleinere Verbesserungen an der Concurrency-Steuerung für ältere Datenbankdateien. Hierzu zählen: • Unterstützung für die Verbindungs-Isolationsebenen Read Uncommitted und Serializable • Es können gemeinsame Tabellensperrungen für Lesevorgänge verwendet werden. Bei älteren Versionen von Blackfish SQL wurden exklusive Tabellensperrungen für Lese- und Schreibvorgänge verwendet. Verbindungs-Pooling bei Blackfish SQL für Windows In einer Anwendung, die viele Datenbankverbindungen öffnet und schließt, ist es sinnvoll, nicht verwendete Connection-Objekte für die künftige Wiederverwendung in einem Pool aufrechtzuerhalten. Dadurch muss nicht jedesmal, wenn eine Verbindung geöffnet wird, eine neue physische Verbindung hergestellt werden. Den DBXClient dbExpress-Treiber verwenden Verwenden Sie den Delegationstreiber TDBXPool, um Verbindungs-Pooling-Unterstützung für DBXClient-Verbindungen bereitzustellen. ADO.NET-Provider verwenden Standardmäßig implementieren die .NET-Client-Treiber einen Verbindungs-Pool, der immer in Kraft ist. Jeder ConnectionString besitzt seinen eigenen Pool. Es gibt Verbindungseigenschaften, die sich auf die Höchstzahl an Verbindungen in einem Pool und weitere Attribute auswirken. Außerdem gibt es eine ConnectionPool-Eigenschaft, die Zugriff 18 3 Blackfish SQL auf alle aktiven Verbindungs-Pools ermöglicht. Verbindungs-Pools und Unterstützung verteilter Transaktionen bei Blackfish SQL für Java Blackfish SQL enthält mehrere Komponenten für die Verwendung von JDBC-DataSources, Verbindungs-Pooling und die Unterstützung verteilter Transaktionen (XA). Diese Funktionen benötigen J2EE. Wenn Sie eine JRE-Version ausführen, die älter als 1.4 ist, müssen Sie die Datei J2EE.jar von java.sun.com herunterladen und sie dem Klassenpfad hinzufügen. Blackfish für Java-Verbindungs-Pooling Das JdbcConnectionPool-Objekt unterstützt XA-Transaktionen. Mithilfe dieser Funktion kann sich Blackfish SQL als Ressourcen-Manager an einer verteilten Transaktion beteiligen. Blackfish SQL bietet XA-Unterstützung durch Implementierung dieser Standardschnittstellen, die von Sun in der Java Transaction API- (JTA-) Spezifikation angegeben werden: • javax.sql.XAConnection • javax.sql.XADataSource • javax.transaction.xa.XAResource Um von einem JdbcConnectionPool-Objekt aus eine verteilte Verbindung zu einer Blackfish SQL-Datenbank herzustellen, rufen Sie die JdbcConnectionPool.getXAConnection()-Methode auf. Die von dieser Methode zurückgegebene Verbindung funktioniert nur mit dem Blackfish SQL-JDBC-Treiber. XA-Unterstützung ist nur hilfreich, wenn sie mit einer verteilten Transaktionsverwaltung, beispielsweise der vom Borland Enterprise Server bereitgestellten, kombiniert wird. Im normalen Betrieb sollten alle globalen Transaktionen bestätigt oder rückgängig gemacht werden, bevor das entsprechende XAConnection-Objekt geschlossen wird. Nimmt eine Verbindung an einer globalen Transaktion teil, die noch nicht den Status "vorbereitet", jedoch den Status "erfolgreich"oder "deaktiviert"hat, wird die Transaktion bei einem eventuellen Crash Recovery rückgängig gemacht (rollback). Die erweiterte JDBC-Eigenschaft "heuristicCompletion" Blackfish SQL bietet heuristicCompletion, eine erweiterte JDBC-Eigenschaft, mit der Sie das Verhalten steuern können, wenn in einer oder mehreren Datenbanken während des Two-Phase-Commits ein Fehler auftritt. Wenn XA-Transaktionen vorbereitet, aber nicht fertig gestellt werden (kein Commit oder Rollback), wird das Verhalten durch eine der folgenden Eigenschaftseinstellungen bestimmt: • commit bestätigt die Transaktion heuristisch, wenn Blackfish SQL die Datenbank neu öffnet. Dies ist die Vorgabe. • rollback setzt die Transaktion heuristisch zurück, wenn Blackfish SQL die Datenbank neu öffnet. • none behält den Transaktionsstatus bei, wenn Blackfish SQL die Datenbank neu öffnet. Wenn diese Option verwendet wird, werden die beim Vorbereiten der Transaktion gehaltenen Sperren neu aktiviert und beibehalten, bis die Transaktion von einem JTA/JTS-kompatiblen Transaktions-Manager bestätigt oder rückgängig gemacht wird. Die heuristischen commit- und rollback-Optionen ermöglichen eine effizientere Ausführung, denn Sperren können früher freigegeben und es werden weniger Einträge in die Transaktions-Protokolldatei geschrieben. Der Blackfish SQL-Hochverfügbarkeitsserver HINWEIS: Diese Funktion ist nur bei Blackfish SQL für Java verfügbar. In Blackfish SQL für Windows ist sie derzeit nicht verfügbar. Bei Datenbankanwendungen ist es sehr wichtig, einzelne Fehlerquellen auszuschließen. Der Blackfish SQL-Server bietet eine Reihe von Funktionen, um Datenbankanwendungen fehlersicher zu machen, indem Ausfallzeiten und der Verlust wichtiger Daten verhindert werden. Der Hochverfügbarkeitsserver verwendet Spiegelungstechniken zur Gewährleistung der Datenverfügbarkeit im Falle von Software- oder Hardware-Fehlern und als Methode für regelmäßige inkrementelle Backups. Obwohl ein ähnlicher Schutz auch durch eine allgemeinere Datenbankreplizierung gegeben ist, bietet der Spiegelungsansatz Vorteile hinsichtlich Einfachheit, Benutzerfreundlichkeit und Leistung. Eine allgemeinere Datenreplizierungslösung könnte für viele der Probleme verwendet werden, die mithilfe des Blackfish 19 3 Blackfish SQL 3 SQL-Hochverfügbarkeitsservers gelöst werden. Obwohl eine allgemeinere Lösung mehrere, unterschiedliche Synchronisierungsprobleme lösen könnte, würde dies jedoch zu höheren Kosten, einer größeren Komplexität und einer schwächeren Leistung führen. Die Blackfish SQL-Datenbank-Engine verwendet die transaktionalen Protokolldateien zur Verwaltung von schreibgeschützten Spiegelungs-Images einer Datenbank. Die für den allgemeinem Datenbankzugriff verwendeten TCP/IP-Datenbankverbindungen werden außerdem zur Synchronisierung der gespiegelten Datenbanken eingesetzt. Spiegelungstypen 3 Diese Spiegelungstypen können von einer Anwendung verwendet werden: • Primär • Schreibgeschützt • Verzeichnis Die primäre Spiegelung Die primäre Spiegelung ist die einzige Spiegelungsart, die sowohl Schreib- als auch Lesezugriffe auf die Datenbank zulässt. Es kann jeweils immer nur eine primäre Spiegelung geben. Schreibgeschützte Spiegelungen Es kann eine beliebige Anzahl von schreibgeschützten Spiegelungen geben. Über die Verbindungen zu diesen Datenbanken können nur Lesevorgänge ausgeführt werden. Schreibgeschützte Spiegelungen bieten eine konsistente Ansicht der Transaktionen der primären Spiegeldatenbank. Schreibgeschützte Spiegeldatenbanken zeigen jedoch möglicherweise nicht immer die aktuellsten Schreibvorgänge in der primären Spiegeldatenbank an. Schreibgeschützte Spiegelungen können mit den Änderungen an der primären Spiegelung sofort, nach einem Zeitplan oder manuell synchronisiert werden. Für das automatische Failover ist die sofortige Synchronisierung erforderlich. Geplante und manuelle Synchronisierungen können für die inkrementelle Synchronisierung oder Backups verwendet werden. Verzeichnisspiegelungen Verzeichnisspiegeldatenbanken spiegeln nur die Spiegelungskonfigurationstabelle und die für die Sicherheitsdefinition benötigten Tabellen. Sie reflektieren nicht die tatsächlichen Anwendungstabellen der primären Spiegelung. Es kann eine beliebige Anzahl von Verzeichnisspiegelungen geben. Über die Verbindungen zu diesen Datenbanken können nur Lesevorgänge ausgeführt werden. Die Speicheranforderungen für eine Verzeichnisspiegeldatenbank sind sehr gering, da sie nur die Spiegeltabelle und die Sicherheitstabellen enthält. Verzeichnisspiegelungen leiten Verbindungsanforderungen zum Lesen an die schreibgeschützten Spiegelungen um. Verbindungsanforderungen zum Schreiben werden an die primäre Spiegelung umgeleitet. Die Blackfish SQL-Engine und Failover Die Failover-Behandlungsfunktionen für die Blackfish SQL-Engine schließen Folgendes mit ein: • Transaktionsprotokolldatensätze • Automatisches Failover • Manueller Failover Transaktionsprotokolldatensätze Blackfish SQL verwendet Transaktionsprotokolldatensätze für die inkrementelle Aktualisierung von Spiegeldatenbanken. Es überträgt diese Protokolldatensätze während der Synchronisierungsvorgänge mit hoher Geschwindigkeit an die Spiegelungen. 20 3 Blackfish SQL Für Änderungen wird derselbe Mechanismus verwendet, der auch für Crash Recovery und Rollbacks zum Einsatz kommt. Für alle Synchronisierungen wird vorhandener Code verwendet. Die vorhandene Unterstützung für Nur-Lese-Transaktionen von Blackfish SQL bietet eine konsistente Ansicht der Transaktionen der gespiegelten Daten, während die Spiegelung mit dem Inhalt neuerer Schreib-Transaktionen aus der primären Spiegeldatenbank synchronisiert wird. Automatisches Failover Wenn eine primäre Spiegeldatenbank ausfällt, die mit mindestens zwei automatischen Failover-Spiegelungen konfiguriert ist, wird eine der schreibgeschützten Spiegeldatenbanken, die als automatische Failover-Spiegelung konfiguriert ist, als primäre Spiegeldatenbank verwendet. Dies hat möglicherweise eine der folgenden Auswirkungen auf die Anwendung: • Wenn eine Anwendung vor dem Ausfall bereits eine Verbindung mit der primären Spiegeldatenbank aufgebaut hat, werden alle versuchten Operationen mit der ausgefallenen primären Spiegeldatenbank die Fehler "SQLException" oder "IOException" auslösen. Die Anwendung kann während des Vorgangs zur neuen primären Spiegeldatenbank wechseln, indem die Transaktion zurückgesetzt (Rollback) wird. Dieser Vorgang ist identisch mit der Behandlung von Datenbank-Deadlocks in OLTP-Anwendungen mit vielen gleichzeitigen Zugriffen. • Wenn eine Anwendung keine Verbindung mit der primären Spiegeldatenbank aufgebaut hat, bevor diese ausgefallen ist, schlägt der Verbindungsversuch fehl. Verzeichnisspiegeldatenbanken können verwendet werden, um neue Verbindungsanforderungen automatisch an die primäre Spiegeldatenbank umzuleiten. Manueller Failover Anders als beim automatischen Failover wird ein manueller Failover nur auf Anforderung durchgeführt. Alle schreibgeschützten Spiegeldatenbanken können zur primären Spiegeldatenbank werden. Dies ist sehr nützlich, wenn der Computer, auf dem der primäre Server ausgeführt wird, zu Wartungszwecken vom Netz getrennt wird. Vorteile des Hochverfügbarkeitsservers Der Blackfish SQL-Hochverfügbarkeitsserver bietet zahlreiche Vorteile einschließlich: • Geringe Anfälligkeit (kein "Single Point of Failure") Da mehrere Kopien derselben Datenbank auf verschiedenen Computern verwaltet werden, besteht kein Bedarf für eine gemeinsam genutzte Speichervorrichtung. Der Hochverfügbarkeitsserver verwaltet die größtmögliche Datenbankverfügbarkeit ohne "Single Point of Failure" und mit Hochgeschwindigkeits-Failover- und Wiederherstellungsmechanismen, garantierter Datenkonsistenz und Transaktionsintegrität. • Umfassende Datensicherheit und Systemausfallschutz Durch die Verwaltung von Datenbankkopien auf mehreren Servern stellt der Hochverfügbarkeitsserver sicher, dass die Daten im Falle eines Medienversagens, bei Serverausfällen oder anderen katastrophalen Ereignissen erhalten bleiben. • Einzelne, konfigurierte Netzwerk-Transportschicht Die Hochleistungs-Transportschicht für aktuelle Datenbankverbindungen wird auch für alle Synchronisierungsvorgänge verwendet. • Portierbarkeit Das Dateiformat und die Synchronisierung ist über alle Plattformen hinweg portierbar, sofern auf diesen Java Virtual Machine ausgeführt werden kann. • Umfassende Kostenersparnis Der Hochverfügbarkeitsserver ermöglicht deutliche Einsparungen hinsichtlich der Kosten für aktuelle Hochverfügbarkeitsgeräte und Arbeitskosten. Er kann auf kostengünstiger Standard-Hardware ausgeführt werden. Es besteht kein Bedarf für spezielle Technologien, wie gemeinsam genutzte Festplatten, private LANs bzw. Glasfaserkabel, oder zusätzliche Software oder Betriebssysteme, wie beispielsweise Linux, Windows, Solaris und Mac OSX. • Einfaches Installieren, Verwalten und Deployment Der Hochverfügbarkeitsserver stellt eine hochleistungsfähige, einfache Lösung für einige häufig vorkommende Datenbankprobleme dar. Es werden keine Clustering-Spezialkenntnisse benötigt. Alle Konfigurationseinstellungen und expliziten Vorgänge können mithilfe der Blackfish SQL-Serverkonsole, SQL-Skripts oder Java-Code vorgenommen bzw. ausgeführt werden. • Verbesserte Skalierbarkeit und Lastverteilung Reine Lesevorgänge können anhand von schreibgeschützten Spiegeldatenbanken vorgenommen werden. So wird die Transaktionsbelastung der primären Spiegeldatenbank reduziert, die für alle Transaktionen mit Schreibvorgängen benötigt wird. Durch die Verbindung mit Verzeichnisspiegeldatenbanken können neuen Verbindungsanforderungen gleichmäßig auf verschiedene schreibgeschützte Spiegeldatenbanken aufgeteilt werden. 21 3 Blackfish SQL 3 Dies reduziert die Arbeitsbelastung des primären Servers in hohem Maße. • Synchronisierungsdelegation Sie können die Spiegeldatenbank angeben, die zum Synchronisieren einer anderen Spiegeldatenbank verwendet wird. So wird ermöglicht, dass die primäre Spiegeldatenbank nur mit einer bzw. einer kleinen Anzahl von schreibgeschützten Spiegeldatenbanken synchronisiert wird. Diese schreibgeschützten Spiegeldatenbanken können anschließend weitere Spiegeldatenbanken synchronisieren. Auf diese Weise wird die Belastung der primären Spiegeldatenbank reduziert, auf der alle Schreibanforderungen ausgeführt werden. • Inkrementelles Datenbank-Backup Schreibgeschützte Spiegeldatenbanken können durch die Planung von einigen Synchronisierungszeiträumen automatisch mit der primären Spiegeldatenbank synchronisiert werden. Schreibgeschützte Spiegeldatenbanken können außerdem für das manuelle Backup verwendet werden, indem eine explizite Synchronisierungsanforderung ausgeführt wird. 3 • Verteiltes Verzeichnis Da dieses Failover-System automatische und manuelle Server-Failover unterstützt, empfiehlt es sich, einen Mechanismus mit verteiltem Verzeichnis für die Suche nach der primären Spiegeldatenbank und verfügbaren schreibgeschützten Spiegeldatenbanken zu verwenden. Alle Spiegelungen verwalten eine Tabelle aller anderen Spiegelungen. Eine Anwendung kann alle Arten von Verbindungsanforderungen ("Lesen/Schreiben" oder "Nur Lesen") an eine beliebige vorhandene Spiegeldatenbank richten. Die Spiegeldatenbank verwendet die Spiegelungstabelle, um festzustellen, wo sich die aktuellen Spiegelungen befinden. Heterogene Replizierung mit Blackfish SQL unter Verwendung von DataExpress HINWEIS: Diese Funktion wird nur bei Blackfish SQL für Java unterstützt. Die Replizierungsunterstützung von DataExpress für Blackfish SQL ist leichter zu verwenden und bereitzustellen als die meisten Replizierungslösungen. Diese Replizierungslösung ist außerdem heterogen, da sie JDBC für den Datenbankzugriff verwendet. Die zur Verfügung gestellte Replizierungstopologie kann am besten als eine einfache Client-Server-Relation beschrieben werden. Blackfish SQL benötigt keine serverseitige Software oder Datenbank-Trigger, die für komplexere Publish-Subscribe-Lösungen erforderlich sind. Komplexe Hierarchie über mehrere Ebenen und Netzwerktopologien werden nicht direkt unterstützt. Bei der Verwendung von DataExpress-JavaBean-Komponenten mit Blackfish SQL für ein verbindungsloses oder mobiles Computing-Modell gibt es drei unterschiedliche Phasen im Replizierungszyklus: • Bereitstellungsphase:Stellt der Client-Datenbank einen Snapshot der zu replizierenden Server-Tabellen zur Verfügung • Bearbeitungsphase:Client-Anwendung, die keine Verbindung zur Datenbank benötigt, liest/bearbeitet die Client-Datenbank • Speicherungsphase:Änderungen an der Client-Datenbank werden in die Server-Datenbank zurückgeschrieben Die Bereitstellungsphase Eine StorageDataSet-Provider-Implementierung repliziert zunächst den Datenbankinhalt vom Server auf einen Client. Der Client ist immer eine Blackfish SQL-Datenbank. Der Server ist in der Regel ein Server, auf den über einen JDBC-Treiber zugegriffen werden kann. Der JDBC-Provider verwendet entweder eine SQL-Abfrage oder eine gespeicherte Prozedur, um die Daten zur Verfügung zu stellen, die in die clientseitige Blackfish SQL-Datenbank repliziert werden. Da in dieser Architektur keine serverseitige Software erforderlich ist, gibt es keine Unterstützung für inkrementelle Aktualisierungen vom Server zum Client. Wenn der Client aktualisiert werden muss, muss dieselbe SQL-Abfrage/gespeicherte Prozedur erneut ausgeführt werden, die für die anfängliche Replizierung verwendet wurde. Ein StorageDataSet-Provider ist eine optionale Schnittstelle.QueryDataSet und ProcedureDataSet sind Erweiterungen von StorageDataSet, die JdbcProviders vorkonfigurieren, die SQL-Abfragen und gespeicherte Prozeduren zum Auffüllen von StorageDataSet mit Daten ausführen können. Für Clients mit beschränktem Arbeitsspeicher, z. B. PDAs, kann eine DataSetData-Komponente zum Bereitstellen der Daten verwendet werden. Die DataSetData-Komponente verwendet die Java-Serialisierung, um ein Datenpaket zu erstellen, das zwischen einem Client und dem Server problemlos übertragen werden kann. Der Bereitstellungsvorgang für Datenbanktabellen kann in einer einzelnen Transaktion ausgeführt werden, sodass eine transaktionskonsistente Ansicht der Tabellen repliziert werden kann. 22 3 Blackfish SQL Die Bearbeitungsphase Wenn die Bereitstellungsphase abgeschlossen ist, können DataExpress und JDBC-APIs in den Blackfish SQL-Tabellen, die die Datenbank replizieren, lesen und schreiben. Alle seit dem letzten Bereitstellungsvorgang ausgeführten Einfüge-/Aktualisierungs-/Lösch- und Schreiboperationen werden vom Blackfish SQL-Speichersystem automatisch verfolgt. In der StorageDataSet-Speicherschnittstelle ist festgelegt, dass alle Einfüge-/Aktualisierungs-/Lösch- und Schreiboperationen aufgezeichnet werden müssen, wenn die StorageDataSet-Eigenschaft auf resolvable gesetzt ist. Die Speicherungsphase DataExpress stellt einen automatischen Mechanismus für die Verwendung von SQL-DML oder gespeicherten Prozeduren zur Verfügung, um alle auf dem Client vorgenommenen Änderungen mithilfe eines JDBC-Treibers auf dem Server zu speichern. Beim Zurückschreiben der Änderungen auf den Server wird der Optimistic-Concurrency-Ansatz verwendet. In einer einzelnen Transaktion können eine oder mehrere Tabellen zurückgeschrieben werden. Standardmäßig führen alle Konflikte, z. B. wenn zwei Benutzer dieselbe Zeile aktualisieren, dazu, dass die Transaktion rückgängig gemacht wird (Rollback). Es gibt jedoch eine SqlResolutionManager-JavaBean-Komponente, die Sie verwenden können, um die Behandlung von Speicherungsfehlern individuell anzupassen. Der SqlResolutionManager verfügt über Ereignisbehandlungsroutinen, die einer Anwendung erlauben, auf einen Fehler mit ignore, retry, abort, log oder einer anderen entsprechenden Antwort zu reagieren. Außerdem gibt es DataStorePump- und DataStoreSync-Komponenten, die Sie verwenden können, um Bereitstellungs- und Speicherungsvorgänge für Tabellen auszuführen. Weitere Informationen hierzu finden Sie unter Administration von Blackfish SQL. Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( see page 43) see page 137) see page 141) 23 3 4 Blackfish SQL 4 4 Verbindungen aufbauen In diesem Kapitel werden die Grundlagen zum Aufbau einer Verbindung zu einer Blackfish SQL-Datenbank mithilfe von dbExpress, ADO.NET oder JDBC erläutert. • Verbindungstypen • dbExpress für die Verbindung zum Server verwenden • ADO.NET für die Verbindung zum Server verwenden • JDBC für die Verbindung zum Server verwenden • Verbindungseigenschaften festlegen • Blackfish SQL mit JBuilder und Borland Enterprise Server verwenden • DataDirectory-Makrounterstützung Verbindungstypen Verbindungen können lokal, remote oder oine Kombination aus beidem sein: • Lokale Verbindungen Lokale Verbindungen greifen prozessintern auf die Blackfish SQL-Datenbank-Engine zu. Dies ermöglicht zwar eine verbesserte Performance eines Remote-Treibers, allerdings muss dafür die Blackfish SQL-Engine vorhanden sein und im gleichen Prozess wie die Anwendung laufen. Verschiedene simultane lokale Verbindungen, die im gleichen Prozess erstellt wurden, können eine Verbindung zur Datenbank herstellen. Eine Datenbankdatei kann jedoch nur von einem Prozess offen gehalten werden. Während ein Prozess eine Datenbankdatei offen hält, ist er folglich der einzige Prozess, der eine Verbindung zu der Datenbank über eine lokale Verbindung herstellen kann. • Remote-Verbindungen Starten Sie zur Verwendung einer Remote-Verbindung zuerst den Blackfish SQL-Server. (Anweisungen hierzu finden Sie unter Administration von Blackfish SQL.) Der Remote-Treiber kommuniziert über TCP/IP mit dem Server. Remote-Verbindungen können bei Datenbank-Interaktionen, die mehrere kleine Datenpakete wechselweise zwischen dem Client und der Datenbank austauschen, langsamer werden. Remote-Verbindungen erlauben es, dass mehrere Prozesse, die auf einem oder mehreren Computern laufen, auf dieselbe Datenbank zugreifen. Falls viele Prozesse simultanen Zugriff benötigen, ist es am besten, Remote-Verbindungen zu verwenden. • Kombination von lokalen und Remote-Verbindungen Eine dritte Möglichkeit ist, die lokalen und Remote-Verbindungen zusammen zu verwenden. Wenn ein Prozess die meisten Interaktionen ausführt, kann dieser Prozess Blackfish SQL innerhalb seines eigenen Prozesses starten. Auf diese Weise kann der Datenbankprozess den lokalen Treiber verwenden und gleichzeitig anderen Prozessen erlauben, auf dieselbe Datenbank mithilfe des Remote-Treibers zuzugreifen. dbExpress für die Verbindung zum Server verwenden Native Anwendungen können dbExpress verwenden, um Remote-Verbindungen mit einem Blackfish SQL-Server aufzubauen. Lokale Verbindungen werden von dbExpress derzeit nicht unterstützt. Sie müssen den Blackfish SQL-Server starten, bevor Sie 25 Blackfish SQL 4 den dbExpress-Remote-Treiber verwenden können. (Anweisungen hierzu finden Sie unter Administration von Blackfish SQL.) Beispiel In diesem Beispiel wird erläutert, wie eine Remote-dbExpress-Verbindung erstellt wird: [BlackfishSQL] uses DBXCommon; uses DBXClient; var Connection: TDBXConnection; Connection := TDBXConnectionFactory.GetConnectionFactory.GetConnection('BLACKFISHSQLCONNECTION'); Die dbExpress-Datei dbxdriver.ini enthält Standardtreibereigenschaften für die meisten Anwendungen. Die dbxconnections.ini BLACKFISHSQLCONNECTION-Abschnitt, dbExpress-Datei enthält einen der die Standardverbindungseinstellungen enthält. Neue Verbindungen können die meisten dieser Eigenschaften kopieren. Diese Liste der Eigenschaften werden in der Regel für neue Verbindungen angepasst: 4 • [BLACKFISHCUSTOMCONNECTION] • HostName=localhost • port=2508 • Database=c:/tmp/test ADO.NET für die Verbindung zum Server verwenden Das Blackfish SQL-Assembly Borland.Data.BlackfishSQL.LocalClient.dll enthält einen ADO.NET 2.0-Treiber. Sie können eine Anwendung mithilfe der DbProviderFactory-Klasse erstellen, ohne dieses Assembly direkt zu referenzieren. Damit dieser Ansatz umgesetzt werden kann, muss die Datei machine.config Referenzen zu den Blackfish SQL-Assemblies im Abschnitt DbProviderFactory enthalten, und die Blackfish SQL-Assemblies müssen im Global Assembly Cache (GAC) installiert sein. Verwenden Sie für ein einfacheres Deployment eine direkte Referenz zum Blackfish SQL-Assembly. Sie können eine lokale ADO-Verbindung, eine Remote-ADO-Verbindung oder eine Kombination aus beidem verwenden, um eine Verbindung zum Blackfish SQL-Server herzustellen. Lokale Verbindungen, die ADO.NET verwenden Sie können eine lokale ADO-Verbindung mit einer der folgenden Möglichkeiten herstellen: • Lokale ADO.NET-Verbindung, die DbProviderFactory verwendet • Lokale ADO.NET-Verbindung, die eine direkte Klassenreferenz verwendet Lokale ADO.NET-Verbindung, die DbProviderFactory verwendet Beispiel Dieses Beispiel verdeutlicht, wie eine lokale ADO-Verbindung mithilfe von DbProviderFactory hergestellt wird: [References: System.Data.dll] uses System.Data.Common; var Factory: DbProviderFactory; var Connection: DbConnection; Factory := DbProviderFactories.GetFactory('Borland.Data.BlackfishSQL.LocalClient'); Connection := Factory.CreateConnection(); Connection.ConnectionString := 'database=<filename>;user=<username>;password=<password>'; Connection.Open; 26 4 Blackfish SQL Lokale ADO.NET-Verbindung, die eine direkte Klassenreferenz verwendet Beispiel Dieses Beispiel verdeutlicht, wie mithilfe einer direkten Klassenreferenz eine lokale ADO-Verbindung hergestellt wird: [References: System.Data.dll] [References: Borland.Data.BlackfishSQL.LocalClient.dll] uses System.Data.Common; uses Borland.Data.DataStore; var Connection: DbConnection; Connection := DataStoreConnection.Create; Connection.ConnectionString := 'database=<filename>;user=<username>;password=<password>'; 4 Connection.Open; Remote-Verbindungen, die ADO.NET verwenden Verwaltete Anwendungen können ADO.NET verwenden, um Remote-Verbindungen mit dem Blackfish SQL-Server aufzubauen. Sie müssen den Server starten, bevor Sie den Remote-ADO-Treiber verwenden können. (Anweisungen hierzu finden Sie unter Administration von Blackfish SQL.) Wenn der Server läuft, können Sie eine Remote-ADO-Verbindung mit einer der folgenden Möglichkeiten herstellen: • Remote-ADO.NET-Verbindung, die DbProviderFactory verwendet • Remote-ADO.NET-Verbindung, die eine direkte Klassenreferenz verwendet Remote-ADO.NET-Verbindung, die DbProviderFactory verwendet Beispiel Dieses Beispiel verdeutlicht, wie mithilfe von DbProviderFactory eine Remote-ADO-Verbindung hergestellt wird: [References: System.Data.dll] uses System.Data.Common; var Factory: DbProviderFactory; var Connection: DbConnection; Factory := DbProviderFactories.GetFactory('Borland.Data.BlackfishSQL.RemoteClient'); Connection := Factory.CreateConnection(); Connection.ConnectionString := 'database=<filename>;user=<username>;password=<password>;host=<servername>;protocol=TCP'; Connection.Open; Remote-ADO.NET-Verbindung, die eine direkte Klassenreferenz verwendet Beispiel Dieses Beispiel verdeutlicht, wie mithilfe einer direkten Klassenreferenz eine Remote-ADO-Verbindung hergestellt wird: [References: System.Data.dll] [References: Borland.Data.BlackfishSQL.RemoteClient.dll] uses System.Data.Common; uses Borland.Data.DataStore; var Connection: DbConnection; Connection := DataStoreConnection.Create; Connection.ConnectionString := 'database=<filename>;user=<username>;password=<password>;host=<servername>;protocol=TCP'; 27 Blackfish SQL 4 Connection.Open; JDBC für die Verbindung zum Server verwenden Sie können eine lokale JDBC-Verbindung, eine Remote-JDBC-Verbindung oder eine Kombination aus beidem verwenden, um eine Verbindung zum Blackfish SQL-Server herzustellen. Die folgenden Abschnitte enthalten Anweisungen für jede dieser Prozeduren. Lokale Verbindungen, die JDBC verwenden Die lokale JDBC-Verbindung des Blackfish SQL ermöglicht, dass eine Anwendung in demselben Prozess wie die Blackfish SQL-Engine ausgeführt wird. Für Anwendungen, die eine Vielzahl von Methodenaufrufen über die JDBC-API realisieren, bedeutet die Verwendung des lokalen Blackfish SQL-Treibers daher eine beträchtliche Leistungssteigerung. Sie können eine lokale JDBC-Verbindung mit einer der folgenden Möglichkeiten herstellen: 4 • Lokale JDBC-Verbindungen mithilfe des Treiber-Managers • Lokale JDBC-Verbindungen mithilfe einer JDBC-Datenquelle Lokale JDBC-Verbindungen mithilfe des Treiber-Managers Beispiel Dieses Beispiel verdeutlicht, wie mithilfe von DriverManager eine lokale JDBC-Verbindung hergestellt wird: [jdsserver.jar must be in classpath] java.sql.DriverManager.registerDriver(new com.borland.datastore.jdbc.DataStoreDriver()); connection = java.sql.DriverManager.getConnection("jdbc:borland:dslocal:<filename>", "<username>", "<password>"); Lokale JDBC-Verbindungen mithilfe einer JDBC-Datenquelle Beispiel Dieses Beispiel verdeutlicht, wie mithilfe einer JDBC-Datenquelle eine lokale JDBC-Verbindung hergestellt wird: [jdsserver.jar must be in classpath] com.borland.javax.sql.JdbcDataSource dataSource = new com.borland.javax.sql.JdbcDataSource(); dataSource.setDatabaseName("<filename>"); connection = dataSource.getConnection("<username>", "<password>"); Remote-Verbindungen, die JDBC verwenden Verwaltete Anwendungen können JDBC verwenden, um Remote-Verbindungen mit dem Blackfish SQL-Server herzustellen. Sie müssen den Server starten, bevor Sie den Remote-ADO-Treiber verwenden können. (Anweisungen hierzu finden Sie unter Administration von Blackfish SQL.) Sie können eine Remote-JDBC-Verbindung mit einer der folgenden Möglichkeiten herstellen: • Remote-JDBC-Verbindungen mithilfe des Treiber-Managers • Remote-JDBC-Verbindungen mithilfe einer JDBC-Datenquelle Remote-JDBC-Verbindungen mithilfe des Treiber-Managers Beispiel Dieses Beispiel verdeutlicht, wie mithilfe von DriverManager eine Remote-JDBC-Verbindung hergestellt wird: [jdsremote.jar must be in classpath] java.sql.DriverManager.registerDriver(new com.borland.datastore.jdbc.DataStoreDriver()); 28 4 Blackfish SQL connection = java.sql.DriverManager.getConnection("jdbc:borland:dsremote://<servername>/<filename>", "<username>", "<password>"); Remote-JDBC-Verbindungen mithilfe einer JDBC-Datenquelle Beispiel Dieses Beispiel verdeutlicht, wie mithilfe einer JDBC-Datenquelle eine Remote-JDBC-Verbindung hergestellt wird: [jdsremote.jar must be in classpath] com.borland.javax.sql.JdbcDataSource dataSource = new com.borland.javax.sql.JdbcDataSource(); dataSource.setDatabaseName("<filename>"); dataSource.setNetworkProtocol("tcp"); datasource.setServerName("<servername>"); 4 connection = dataSource.getConnection("<username>", "<password>"); Verbindungseigenschaften festlegen Sie können Verbindungseigenschaften für folgende Verbindungen angeben: • dbExpress • ADO • JDBC Weitere Informationen finden Sie in der RAD Studio-Hilfe für Borland.Data.DataStore.ConnectionProperties. dbExpress-Verbindungseigenschaften festlegen Die dbExpress-Verbindungseigenschaften sind in der Unit DbxCommon.pas und in der Blackfish ConnectionProperties dokumentiert und werden in der Datei dbxconnections.init gespeichert. SQL-Klasse Beispiel Dieses Beispiel zeigt einen Blackfish SQL-Verbindungseigenschaftenabschnitt in der Datei dbxconnections.ini: [BLACKFISHSQLCONNECTION] DriverName=BlackfishSQL HostName=localhost port=2508 Database=/tmp/test create=true User_Name=sysdba Password=masterkey BlobSize=-1 TransIsolation=ReadCommitted Die Eigenschaften HostName, port und create sind in ConnectionProperties dokumentiert. Die Eigenschaften DriverName, User_Name, BlobSize und TransIsolation sind in TDBXPropertyNames der Unit DBXCommon dokumentiert. ADO-Verbindungseigenschaften festlegen Die Eigenschaft ConnectionString ConnectionProperties enthalten. in DbConnection oder DataStoreConnection kann Einstellungen aus Mit dem Daten-Explorer können Sie Werte für ConnectionProperties setzen und bearbeiten. Anweisungen finden Sie in der RAD Studio-Hilfe für das Daten-Explorer-Verbindungsdialogfeld. JDBC-Verbindungseigenschaften festlegen Sie können JDBC-Verbindungseigenschaften durch eine der beiden folgenden Optionen angeben: 29 Blackfish SQL 4 • eine JDBC-URL • java.util.Properties JDBC-Verbindungseigenschaften in einer JDBC-URL angeben Sie können Verbindungseigenschaften in einer JDBC-URL angeben. Trennen Sie dabei die Eigenschaften mithilfe von Semikolons: jdbc:borland:dslocal:c:/mydb.jds;create=true JDBC-Verbindungseigenschaften mit java.util.Properties angeben 4 Beispiel Dieses Beispiel verdeutlicht, wie JDBC-Verbindungseigenschaften mithilfe eines java.util.Properties-Objekts angegeben werden: java.util.Properties props = new java.util.Properties(); props.setProperty("create","true"); props.setProperty("user","SYSDBA"); props.setProperty("password","masterkey"); connection = DriverManager.getConnection("jdbc:borland:dslocal:c:/mydb.jds", props); Blackfish SQL mit JBuilder und Borland Enterprise Server verwenden Damit die neueste Version von Blackfish SQL für JBuilder und Borland Enterprise Server (BES) zur Verfügung steht, müssen Sie bestimmte Dateien vom JDataStore-lib-Verzeichnis in das lib-Verzeichnis des Zielprodukts kopieren: • beandt.jar • dbtools.jar • dx.jar • jds.jar • jdsremote.jar • jdsserver.jar 1. Suchen Sie für JBuilder oder BES zuerst die aufgelisteten Dateien im lib-Verzeichnis des Installationsbaums und kopieren Sie sie in ein Backup-Verzeichnis. 2. Suchen Sie die Dateien im lib-Verzeichnis des installierten Blackfish SQL-Produkts und kopieren Sie sie in das lib-Verzeichnis von JBuilder oder BES. Unterstützung für DataDirectory-Makros Mit dem DataDirectory-Makro können Sie relative Pfadnamen für Datenbankdateien angeben. Das DataDirectory-Makro wird von den Blackfish SQL-ADO.NET- und DBXClient-Treibern unterstützt. Wenn einem Datenbankdateinamen der folgende String vorangestellt wird: |DataDirectory| beispielsweise: |DataDirectory|employee.jds wird der String |DataDirectory| wie folgt durch den entsprechenden String ersetzt: Blackfish SQL für Windows: • Bei webbasierten ASP.NET-Anwendungen ist dies der Ordnername App_Data. • Bei nicht-Web-Anwendungen ist dies standardmäßig das Verzeichnis der ausführbaren Datei der Anwendung. Sie kännen die 30 4 Blackfish SQL Vorgabe überschreiben, indem Sie die Eigenschaft DataDirectory für AppDomain setzen: AppDomain.CurrentDomain.SetData("DataDirectory", "CustomAppPath") Blackfish SQL für Java: Wenn die Systemeigenschaft blackfishsql.datadirectory gesetzt ist, wird die Einstellung für diese Eigenschaft als Ersetzungs-String verwendet. Anderenfalls wird die Einstellung der user.home-Eigenschaft verwendet. Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Administration von Blackfish SQL ( 4 see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( see page 43) see page 137) see page 141) 31 5 Blackfish SQL 5 Administration von Blackfish SQL 5 Dieses Kapitel enthält eine kurze Übersicht der administrativen Verfahren und Tools für Blackfish SQL. Weitere Informationen hierzu finden Sie in der SQL-Referenz. • Grafische Konsolen für administrative Tasks verwenden • SQL für administrative Tasks verwenden • Blackfish SQL Server starten Grafische Konsolen für administrative Tasks verwenden Sie können grafische Tools zur Verwaltung von Blackfish SQL verwenden. Blackfish SQL für Windows: Sie können den RAD Studio Daten-Explorer zur Durchführung vieler administrativer Tasks verwenden. Der Daten-Explorer wurde um einen Verbindungs-String-Editor für Blackfish SQL für Windows erweitert und es ist nun möglich, Blackfish SQL-Datenbanken zu erstellen und zu bearbeiten. Mit dem Daten-Explorer können Sie gespeicherte Prozeduren durchsuchen und anzeigen. Einige Daten-Explorer-Tasks werden von Blackfish SQL für Windows noch nicht unterstützt. Weitere Informationen finden Sie in der Daten-Explorer-Hilfe. Blackfish SQL für Java: Sie können eine der JBuilder-Administrationskonsolen verwenden. • JdsExplorer • ServerConsole Die Dokumentation für JdsExplorer und ServerConsole sind in JBuilder enthalten. SQL für administrative Tasks verwenden Sie können nahezu alle administrativen Aufgaben für Blackfish SQL entweder mithilfe von SQL-Befehlen oder unter Vewendung der integrierten gespeicherten Prozeduren in der DB_ADMIN-Klasse durchführen. Verwenden Sie administrative SQL-Befehle zum: • Erstellen, Ändern und Entfernen von Tabellen und Ansichten • Erstellen, Ändern und Entfernen von Benutzern und Rollen • Erstellen und Entfernen von gespeicherten Prozeduren und Triggern. 33 Blackfish SQL 5 Weitere Informationen hierzu finden Sie in der SQL-Referenz. Verwenden Sie gespeicherte DB_ADMIN-Prozeduren zum: • Bearbeiten von Datenbankeigenschaften • Verifizieren einer Datenbank • Konfigurieren der Datenbankprotokollierung • Ansehen von geöffneten Serververbindungen • Erstellen, Ändern und Entfernen von Datenbankspiegelungen • Einsatz verschiedener Administrationsfunktionen für die Spiegelung Weitere Informationen hierzu finden Sie unter Gespeicherte Prozeduren - Referenz. Blackfish SQL Server starten und stoppen Ein Server muss laufen, bevor eine Remote-Verbindung hergestellt werden kann. Der Server kann als .NET- oder Java-Prozess gestartet werden. 5 Starten und Stoppen des Servers als .NET-Prozess Zum Starten und Stoppen des Servers als .NET-Prozess verwenden Sie entweder: • Den Befehl BSQLServer.exe • Die Windows Management Console BSQLServer.exe verwenden • So starten Sie den Server: BSQLServer.exe • So stoppen Sie den Server: BsqlServer.exe -shutdown oder geben Sie Strg-C im Konsolenfenster ein. • So installieren Sie den Server als Windows-Dienst: BsqlServer.exe -install • So entfernen Sie den Server: BsqlServer.exe -remove • So rufen Sie andere Optionen zur Serverkonfiguration auf: BsqlServer.exe -? Die Windows Management Console verwenden • So starten Sie den Server: net start BlackfishSQL • So stoppen Sie den Server: net stop BlackfishSQL Server als Java-Prozess starten Zum Starten und Stoppen des Servers als .NET-Prozess verwenden Sie entweder: • Den Befehl JdsServer.exe • Die Windows Management Console JdsServer.exe verwenden • So starten Sie den Server: JdsServer.exe • So stoppen Sie den Server: JdsServer.exe -shutdown oder geben Sie Strg-C im Konsolenfenster ein. 34 5 Blackfish SQL • So installieren Sie den Server als Windows-Dienst: JdsServer.exe -install JDataStore • So entfernen Sie den Windows-Server: JdsServer.exe -remove JDataStore • So rufen Sie andere Optionen zur Serverkonfiguration auf: JdsServer.exe -? Die Windows Management Console verwenden • So starten Sie den Server: net start JDataStore • So stoppen Sie den Server: net stop JDataStore Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Sicherheitsfunktionen von Blackfish SQL ( 5 see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( see page 43) see page 137) see page 141) 35 6 Blackfish SQL 6 Sicherheitsfunktionen von Blackfish SQL Dieses Kapitel enthält eine kurze Übersicht der grundlegenden administrativen Funktionen von Blackfish SQL und der SQL-Befehle, die Sie zur Implementierung verwenden können. Eine komplette Beschreibung der Syntax und Anwendung sowie Beispiele für spezifische Befehle finden Sie in der SQL-Referenz oder der Gespeicherte Prozeduren - Referenz. Blackfish SQL bietet die folgenden integrierten Sicherheitsfunktionen: • Benutzerauthentifizierung • Benutzerautorisierung • Datenbankverschlüsselung Benutzerauthentifizierung Die Benutzerauthentifizierung beschränkt den Zugriff auf eine Blackfish SQL-Datenbank auf autorisierte Benutzer. Benutzer müssen sich mit einem autorisierten Benutzerkonto und Passwort bei der Datenbank anmelden. Berechtigungen können einem Konto gewährt und entzogen werden, um den Zugriff genauer einzugrenzen. Im Allgemeinen ist der Vollzugriff für das Administratorkonto reserviert. Eingeschränkte Konten werden für allgemeine Benutzer bereitgestellt. Das Administrator-Konto Standardmäßig hat Blackfish SQL ein integriertes Administrator-Konto: sysdba/masterkey. Sie können eine Datenbank absichern, indem Sie das Passwort für das sysdba-Konto ändern und die Verwendung dieses Kontos auf Datenbankadministratoren beschränken. Anschließend können Sie ein Benutzerkonto mit eingeschränkten Zugriffsrechten für den allgemeinen Zugriff erstellen. Außerdem können Sie zusätzliche Administratorkonten einrichten, denen Datenbank-Startberechtigungen gewährt oder verweigert werden können. Der folgende Abschnitt beschreibt die Erstellung und Bearbeitung von Benutzerkonten. Benutzerkonten verwalten Sie können die folgenden SQL-Anweisungen verwenden, um Benutzerkonten hinzuzufügen, zu löschen und zu ändern: Benutzer hinzufügen CREATE <userid> PASSWORD <password> 37 6 Blackfish SQL 6 wobei: <userid> ist das hinzuzufügende Konto <password> ist das Passwort für dieses Konto Benutzer entfernen DROP <userid> [ CASCADE|RESTRICT ] wobei: <userid> ist das zu löschende Konto CASCADE entfernt den Benutzer und alle Objekte, die er besitzt. Bei Verwendung von RESTRICT schlägt die Anweisung fehl, wenn der Benutzer Eigentümer von Objekten, wie beispielsweise Tabellen, Ansichten oder Methoden, ist. Ohne Option schlägt die Anweisung fehl, wenn der Benutzer Eigentümer von Objekten, wie beispielsweise Tabellen, Ansichten oder Methoden, ist. Ein Benutzerpasswort ändern ALTER USER <userid> SET PASSWORD "<password>"; wobei: 6 <userid> ist das Konto, für das das Passwort geändert werden soll. <password> ist das neue Passwort. Benutzerautorisierung Es gibt einige Datenbankzugriffsberechtigungen, die Sie einem Konto gewähren oder verweigern können. Der folgende Abschnitt Beschreibt das Set von Zugriffsberechtigungen und wie Berechtigungen für ein Konto gewährt oder verweigert werden. Benutzerzugriffsberechtigungen ändern Mithilfe der Anweisungen GRANT und REVOKE können Sie die Zugriffsberechtigungen für ein oder mehrere Benutzerkonten ändern. Sie können den Zugriff auf spezifische Datenbankressourcen oder spezifische Objekte in der Datenbank gewähren oder verweigern. Zusätzlich können Sie benannten Rollen spezielle Berechtigungen gewähren und diese Rollen spezifischen Benutzern gewähren und entziehen. Verwenden Sie die folgenden SQL-Befehle, um einem Konto Berechtigungen zu gewähren oder zu entziehen: GRANT <role>|<privilege> TO <userid> Gewährt dem angegebenen Benutzerkonto die angegebene Berechtigung oder Rolle. REVOKE <role>|<privilege> FROM <userid> Entzieht dem angegebenen Benutzerkonto die angegebene Berechtigung oder Rolle. wobei: <userid> das zu ändernde Konto ist. <role> die Benutzerrolle ist, die gewährt oder verweigert werden soll, z. B. ADMIN. Dies kann eine einzelne Rolle oder eine durch Komma getrennte Liste von Rollen sein. <privilege> die Berechtigung ist, die gewährt oder verweigert werden soll. Dies kann eine einzelne Berechtigung bzw. eine durch Komma getrennte Liste von Berechtigungen sein. Eine oder mehrere der folgenden Berechtigungen kommen dabei in Frage: 38 6 Blackfish SQL • STARTUP gewährt das Recht, eine geschlossene Datenbank zu öffnen. Zum Vergeben von STARTUP-Rechten an ein Benutzerkonto ist dessen Passwort erforderlich. STARTUP-Rechte können auch angegeben werden, wenn das Benutzerkonto hinzugefügt wird. • ADMINISTRATOR gewährt Rechte zum Hinzufügen und Entfernen von Benutzern, zur Änderung von Benutzerrechten und zum Verschlüsseln der Datenbank. Umfasst die vier Datenstromrechte: WRITE, CREATE, DROP, RENAME. Beim Anlegen des Administratorkontos werden ihm automatisch STARTUP Rechte zugeteilt. Diese STARTUP-Rechte können einem Administrator jedoch entzogen werden. Sie können die Berechtigungen WRITE, CREATE, DROP oder RENAME nicht von einem Administratorkonto entfernen. Derartige Versuche werden ignoriert. • WRITE gewährt das Recht, in Datei- oder Tabellenströme einer Blackfish SQL-Datenbank zu schreiben. • CREATE gewährt das Recht, neue Datei- oder Tabellenströme einer Blackfish SQL-Datenbank zu erstellen. • DROP gewährt das Recht, Datei- oder Tabellenströme aus einer Blackfish SQL-Datenbank zu entfernen. • RENAME gewährt das Recht, Datei- oder Tabellenströme einer Blackfish SQL-Datenbank umzubenennen. Datenbankverschlüsselung Nur ein Benutzer mit Administrator-Berechtigung kann eine Datenbank verschlüsseln. Wenn eine Datenbank verschlüsselt ist, wird die STARTUP-Berechtigung automatisch allen Benutzern (einschließlich Administratoren) entzogen mit Ausnahme des Administrators, der den Verschlüsselungsbefehl ausgeführt hat. Infolgedessen müssen Sie nach dem Verschlüsseln dasselbe Administratorkonto zum Neustart der Datenbank verwenden. Sie können STARTUP-Berechtigungen anderen Benutzern neu zuweisen, nachdem die Datenbank verschlüsselt und neu gestartet wurde. Eine Blackfish SQL-Datenbank verschlüsseln Sie können die integrierte gespeicherte Prozedur DB_ADMIN.ENCRYPT() verwenden, um eine neue oder leere Blackfish SQL-Datenbank zu verschlüsseln. Anweisungen zur Verschlüsselung einer nicht leeren Datenbank finden Sie unter Eine Datenbank mit vorhandenen Inhalten verschlüsseln. Zum Verschlüsseln einer neuen Datenbank melden Sie sich mit einem Administratorkonto an und rufen Sie den folgenden SQL-Befehl auf: CALL DB_ADMIN.ENCRYPT(<AdminPassword>,<EncryptionSeed>) wobei: DB_ADMIN.ENCRYPT() die integrierte gespeicherte Prozedur zum Verschlüsseln einer Datenbank ist. <AdminPassword> das Passwort für den Benutzer ist, der den Verschlüsselungsbefehl aufruft. <EncryptionSeed> ein 16 Zeichen langer Seed-Wert ist. Eine Datenbank mit vorhandenen Inhalten verschlüsseln Blackfish SQL für Java: Zum Verschlüsseln einer Blackfish SQL für Java-Datenbank, die Tabellen enthält, verwenden Sie das JBuilder-Dienstprogramm JdsExplorer. Anweisungen finden Sie in der JBuilder-Online-Hilfe für JdsExplorer. Blackfish SQL für Windows: So verschlüsseln Sie eine Datenbank mit vorhandenen Inhalten: 1. Verwenden Sie den RAD Studio Daten-Explorer, um eine neue Datenbank zu erstellen. Anweisungen finden Sie in der Daten-Explorer-Online-Hilfe. 2. Kopieren Sie die vorhandenen Benutzer in die neue Datenbank. DB_ADMIN.COPY_USERS(<OtherFilename>, <AdminUser>, <AdminPass>,<DoCopyEncryption>, <ReplaceExistingUsers>) wobei: <OtherFilename> der Dateiname der Zieldatenbank ist. <AdminUser> ein Benutzer mit ADMIN-Berechtigung in der Zieldatenbank ist. <AdminPass> ein Passwort des angegebenen adminUser in der Zieldatenbank ist. Wenn <DoCopyEncryption> den Wert TRUE hat und die aktuelle Datenbank verschlüsselt ist, verschlüsseln Sie die Zieldatenbank mit demselben Schlüssel. Wenn <ReplaceExistingUsers> den Wert TRUE hat, werden die vorhandenen Benutzer in der Zieldatenbank durch die Benutzer 39 6 Blackfish SQL 6 in der Quelldatenbank ersetzt. 3. Verschlüsseln Sie die neue Datenbank. DB_ADMIN.ENCRYPT(<password>,<EncryptionSeed>) 4. Kopieren Sie die Inhalte der alten Datenbank in die neu verschlüsselte Datenbank. DB_ADMIN.COPY_STREAMS(<OtherFilename>, <AdminUser>, <AdminPass>, <DoOverwrite>, <DoIgnoreErrors>) wobei: <OtherFilename> der Dateiname der Zieldatenbank ist. <AdminUser> ein Benutzer mit ADMIN-Berechtigung in der Zieldatenbank ist. <AdminPass> ein Passwort des angegebenen adminUser in der Zieldatenbank ist. Wenn <DoOverwrite> den Wert TRUE hat, dürfen Tabellen überschrieben werden. Wenn der Wert FALSE ist, tritt ein Fehler auf. Wenn <IgnoreErrors> den Wert TRUE hat, kann mit dieser Methode eine beschädigte Datenbank repariert werden. Weitere Informationen hierzu finden Sie unter Gespeicherte Prozeduren-Referenz. Wie kann Blackfish SQL-Sicherheit eingesetzt werden? Im Folgenden wird jemand, der versucht, in das Blackfish SQL-Sicherheitssystem einzudringen, als Gegner bezeichnet. Bei serverseitigen Anwendungen, bei denen Gegner keinen Zugriff auf die physischen Blackfish SQL-Datenbankdateien haben sollen, bieten die Benutzerauthentifizierung und -autorisierung eine hohe Sicherheit. In der SYS.USERS-Tabelle werden Passwörter, Benutzer-IDs und Rechte in verschlüsselter Form gespeichert. Außerdem werden die Benutzer-ID und die Rechte in einer unverschlüsselten Spalte gespeichert, die aber nur zu Anzeigezwecken dient. Die verschlüsselten Werte für Benutzer-ID und Benutzerrechte dienen der Erhöhung der Sicherheit. Die gespeicherten Passwörter werden mit einer TwoFish-Blockkodierung verschlüsselt. Bei der Verschlüsselung des Passworts wird zudem ein Pseudo-Zufallszahlen-Generator verwendet. Dadurch wird es viel schwieriger, das Passwort durch herkömmliche "Dictionary Attacks" herauszufinden. Bei einem solchen Angriff versucht der Gegner, das Passwort durch Ausprobieren zu erraten. Das ist um so einfacher, wenn der Gegner über persönliche Informationen über den Benutzer verfügt, und der Benutzer ein naheliegendes Passwort gewählt hat. Somit ist der wirksamste Schutz gegen Dictionary Attacks ein gut gewähltes (schwer zu erratendes) Passwort. Nach Eingabe eines verkehrten Passworts ist der aktuelle Thread für 500 Millisekunden inaktiv. 6 Bei einer unverschlüsselten Blackfish SQL-Datenbank ist es aus folgenden Gründen wichtig, den physischen Zugriff auf diese Datei zu beschränken: • Wenn eine Blackfish SQL-Datenbankdatei nicht passwortgeschützt ist und es einem Gegner möglich ist, mit einem separaten Dateieditor in die Datei zu schreiben, kann er die Benutzerauthentifizierung und die Benutzerautorisierung deaktivieren. • Wenn es einem Gegner gelingt, mit einem Dateieditor eine unverschlüsselte Blackfish SQL-Datenbankdatei zu lesen, kann er möglicherweise das Dateiformat entschlüsseln und die Dateiinhalte einsehen. In Umgebungen, in denen ein gefährlicher Gegner Zugriff auf physische Kopien einer Blackfish SQL-Datenbank erhalten kann, sollten die Datenbank- und Protokolldateien nicht nur passwortgeschützt, sondern auch noch verschlüsselt werden. WARNUNG: Die Techniken, die Blackfish SQL zum Verschlüsseln von Datenblöcken verwendet, sind auf dem neuesten Stand. Die TwoFish-Blockkodierung, die Blackfish SQL verwendet, wurde noch nie geknackt. Dies bedeutet, dass Sie nicht mehr auf die Datenbank zugreifen können, wenn Sie Ihr Passwort für eine verschlüsselte Blackfish SQL-Datenbank vergessen haben. In so einem Fall hätten Sie noch die beste Aussicht auf Rettung Ihrer Daten, wenn Sie jemanden das Passwort erraten lassen. Es gibt jedoch Maßnahmen, um zu verhindern, dass man das Passwort für eine verschlüsselte Datenbank vergisst. Zunächst einmal sollte man wissen, dass intern ein Master-Passwort für das Verschlüsseln der Datenblocks verwendet wird. Jeder Benutzer mit STARTUP-Rechten verschlüsselt das Master-Passwort mit seinem eigenen Passwort in der SYS.USERS-Tabelle. Dadurch können ein oder mehrere Benutzer eine geschlossene Datenbank öffnen, weil sie mit ihrem Passwort eine Kopie des Master-Passworts entschlüsseln können. Mit dieser Funktion kann man eine neue Datenbank mit einem geheimen Benutzer mit Administratorberechtigungen (einschließlich STARTUP-Rechten) erstellen. Wenn diese leere Datenbank als Basis für alle folgenden, neuen Datenbanken verwendet wird, gibt es immer einen geheimen Benutzer, der die Daten entschlüsseln kann. Das Verschlüsseln von Datenbanken hat Auswirkungen auf die Leistung. Datenblöcke werden verschlüsselt, wenn sie aus dem Blackfish SQL-Cache in die Blackfish SQL-Datenbank geschrieben werden und sie werden entschlüsselt, wenn sie aus der Blackfish SQL-Datenbank in den Blackfish SQL-Cache eingelesen werden. Dadurch werden die Geschwindigkeitsverluste durch das Verschlüsseln auf das Schreiben und Auslesen der Daten beschränkt. 40 6 Blackfish SQL Blackfish SQL verschlüsselt alles, bis auf die ersten 16 Byte von .jds-Dateidatenblöcken. In diesen ersten 16 Byte eines Datenblocks befinden sich keine Benutzerdaten. Manche Blöcke werden nicht verschlüsselt. Dazu zählen Zuordnungs-Bitmaps, der Header-Block, Protokollverankerungsblöcke und die SYS.USERS-Tabellenblöcke. Die schützenswerten Felder in der SYS.USERS-Tabelle werden übrigens mit dem benutzereigenen Passwort verschlüsselt. Protokolldateiblöcke werden vollständig verschlüsselt. Protokollverankerungs- und Statusprotokolldateien werden nicht verschlüsselt. Die temporäre Datenbank, die von der Abfrage-Engine verwendet wird, ist verschlüsselt. Sortierdateien, die bei umfangreichen Sortiervorgängen beim Zusammenführen verwendet werden, werden zwar nicht verschlüsselt, aber nach Beenden des Sortiervorgangs gelöscht. HINWEIS: Der Remote-Client für Blackfish SQL verwendet derzeit Sockets zur Kommunikation mit einem Blackfish SQL-Server . Diese Kommunikation ist als solche nicht sicher. Durch den Einsatz des lokalen Clients für Blackfish SQL ist sie jedoch sicher. Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( 6 see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( see page 43) see page 137) see page 141) 41 7 Blackfish SQL 7 Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden Blackfish SQL unterstützt gespeicherte Prozeduren zum Verkapseln der Geschäftslogik in das Schema einer Datenbank. Zusätzlich unterstützt Blackfish SQL benutzerdefinierte Funktionen (UDFs) zur Erweiterung des integrierten SQL-Supports. Während viele Datenbankhersteller ihre eigene SQL-ähnliche Sprache für gespeicherte Prozeduren entwickelt haben, kann Blackfish SQL gespeicherte Prozeduren und UDFs verwenden, die in einer beliebigen .NET-Sprache, wie z. B. Delphi, C#, VB und Java, erstellt wurden. Gespeicherte Prozeduren können die Leistung einer Anwendung erhöhen, da sie in der gleichen Virtual Machine wie die Blackfish SQL-Datenbank-Engine selbst ausgeführt werden. Dies führt zu einer Ausführung mit minimalem Overhead. Während eine gespeicherte Prozedur SQL-Anweisungen ausführt, wird kein Netzwerkverkehr generiert. Die gespeicherte Prozedur verwendet eine prozessinterne ADO.NET-Verbindung. Dies bietet den gleichen Leistungsvorteil wie die Verwendung des prozessinternen Blackfish SQL-ADO.NET-Treibers anstatt des Remote-Treibers. Gespeicherte Prozeduren und UDFs bieten diese zusätzlichen Vorteile: • Geschäftslogik, wie z. B. definierte Bedingungen zur Gewährleistung der Datenintegrität, ist in der Datenbank-Engine isoliert, wo die Logik verfügbar ist und auf alle Clients angewendet werden kann. • Daten werden lokal abgerufen, was schneller ist als das Senden dieser Daten zum und vom Client. • Die Blackfish SQL-Sprache kann mit C#-, Delphi- oder Visual Basic-Funktionen erweitert werden. • Es gibt keine Leistungeinbußen, da die gespeicherten Prozeduren in der gleichen Virtual Machine wie die Datenbank selbst ausgeführt werden. • Sie können gespeicherte .NET-Prozeduren auf die gleiche Weise wie die Client-Anwendung debuggen. In diesem Kapitel finden Sie folgende Themen: • Allgemeines zu gespeicherten Prozeduren • Allgemeines zu benutzerdefinierten Funktionen (UDFs) • Gespeicherte Prozeduren für die .NET-Plattform erstellen • Gespeicherte .NET-Prozeduren debuggen • Eine gespeicherte Prozedur verwenden, um einen ADO.NET-IDataReader zu erzeugen • Gespeicherte Prozeduren für die Java-Plattform erstellen 43 7 Blackfish SQL 7 Allgemeines zu gespeicherten Prozeduren Gespeicherte Prozeduren sind Prozeduren, die auf dem Datenbank-Server gespeichert sind und auf Anforderung eines SQL-Clients ausgeführt werden. Häufig führt die gespeicherte Prozedur mehrere SQL-Abfragen auf Tabellen in der Datenbank durch, um das gewünschte Ergebnis auszugeben. In Blackfish SQL können diese SQL-Abfragen in einer Sprache Ihrer Wahl geschrieben sein, die auf den .NET- oder Java-Plattformen verfügbar ist. Der gewünschte Effekt kann die Aktualisierung eines Tabellensets, die Berechnung eines akkumulierten Wertes von einer oder mehreren Tabellen oder das Hinzufügen spezieller Integritätsbedingungen sein. Eine gespeicherte Prozedur kann mehrere Parameter haben, die entweder nur dem Input, nur dem Output oder beidem dienen. Beispiel Angenommen, eine ADD_ORDER-Prozedur, die einen customerId-Wert, einen itemId-Wert und einen quantity-Wert als Input nimmt, fügt einen Datensatz zur ORDERS-Tabelle hinzu. Setzen Sie dabei voraus, dass Sie auch überprüfen möchten, dass dieser Kunde für vorherige Aufträge bezahlt hat. Um dies zu erreichen, können Sie bewirken, dass die Prozedur eine Exception auslöst, falls das nicht der Fall sein sollte. Die gespeicherte Prozedur wird mit einem IDbCommand-Objekt ausgeführt, indem die Eigenschaften CommandType und CommandText gesetzt und anschließend die entsprechenden Parameter hinzugefügt werden. CommandText CommandType Parameter 'CALL ADD_ORDER(?,?,?)' CommandType.Text Hinzugefügt in dieser Reihenfolge (von links nach rechts) 'CALL CommandType.Text ADD_ORDER(:CUSTID,:ITEMID,:QUANTITY)' 'ADD_ORDER' 7 Hinzugefügt durch Namen der Markierung CommandType.StoredProcedure Hinzugefügt durch Namen des Parameters Beachten Sie den Unterschied in der Interpretation der Parameter, abhängig von der Kombination von CommandType und dem Stil der Parametermarkierungen, die verwendet werden. Wenn CommandType vom Typ StoredProcedure ist, werden die Parameternamen aus der Implementierung der gespeicherten Prozedur entnommen, wodurch es möglich wird, optionale Parameter auszulassen. Allgemeines zu benutzerdefinierten Funktionen (UDFs) Eine benutzerdefinierte Funktion ist ein Code-Baustein, der zur Erweiterung des integrierten SQL-Supports geschrieben wurde. Genau wie gespeicherte Prozeduren werden sie auf dem Datenbank-Server ausgeführt und von einem SQL-Client aufgerufen. Benutzerdefinierte Funktionen müssen einen Wert zurückgeben und und werden üblicherweise geschrieben, damit sie in der WHERE-Klausel von SELECT-Abfragen verwendet werden können. Eine benutzerdefinierte Funktion kann jedoch auch von sich selbst aufgerufen werden, ähnlich einer gespeicherten Prozedur. Beispiel Angenommen, eine MAX_VALUE-Funktion nimmt zwei Werte (<value1> und <value2>) und gibt den größeren der beiden zurück. Die benutzerdefinierte Funktion kann in einer SQL-Anweisung ausgeführt werden: 'SELECT * FROM PEOPLE WHERE MAX_VALUE(HEIGHT,5*WIDTH) < ?' Oder, in einer SQL-CALL-Anweisung: '?=CALL MAX_VALUE(?,?)' Gespeicherte Prozeduren für die .NET-Plattform erstellen Dieser Abschnitt bietet ausführliche Informationen zum Erstellen gespeicherter Prozeduren für Blackfish SQL und benutzerdefinierter Funktionen für die .NET-Plattform. Eine gespeicherte Prozedur für eine Blackfish SQL-Datenbank erstellen Zum Erstellen einer gespeicherten Blackfish SQL-Prozedur sind drei Schritte erforderlich: 44 7 Blackfish SQL 1. Schreiben Sie den Code für die gespeicherte Prozedur als einen statischen öffentlichen Member einer Klasse. 2. Erstellen Sie ein Assembly mit den gespeicherten Prozeduren. Blackfish SQL muss das Assembly finden können. Wenn Sie in Delphi entwickeln, kann Blackfish SQL das Assembly in BDSCOMMONDIR finden. Dies bedeutet, es ist nicht erforderlich, das Assembly an einen speziellen Speicherort zu verschieben. Für das Deployment wird empfohlen, dass Sie das Assembly in das Unterverzeichnis kopieren, in dem sich die ausführbare Datei für den Blackfish SQL-Server (BSQLServer.exe) befindet, oder installieren Sie es in den Global Assembly Cache (GAC). 3. Erstellen Sie die Bindung eines SQL-Bezeichners für das Assembly-Member. Beispiel Dieses Beispiel verwendet ADD_ORDER aus dem vorherigen Beispiel in Allgemeines zu gespeicherten Prozeduren mit diesem Schema: KUNDENTABELLE Feld Typ Beschreibung CUST_ID INT Kundenbezeichner CREDIT DECIMAL(10,2) Für den Kunden verfügbares Kreditvolumen NAME VARCHAR(80) Kundenname AUFTRAGSTABELLE Feld Typ Beschreibung CUST_ID INT Kundenbezeichner ITEM_ID INT Elementbezeichner QUANTITY INT Wie viele Elemente SALE_AMOUNT DECIMAL(10,2) Gesamtbetrag PAID DECIMAL(10,2) Gezahlter Betrag 7 PRODUKTTABELLE Feld Typ Beschreibung ITEM_ID INT Elementbezeichner NAME VARCHAR(60) Name des Produkts PRICE DECIMAL(10,2) Stückpreis STOCK INT Lageranzahl Schritt 1: Code für die gespeicherte Prozedur schreiben. 1. Erstellen Sie ein Delphi.NET-Paket und nennen Sie es MyProcs.dll. 2. Fügen Sie eine Referenz zu System.Data.dll hinzu. 3. Fügen Sie eine Einheit hinzu: P1 := Command.Parameters.Add('P1', DbType.Decimal); P2 := Command.Parameters.Add('P2', DbType.Int32); P1.Direction := ParameterDirection.Output; P2.Value := CustId; Command.ExecuteNonQuery; if P1.Value = DBNull.Value then 45 Blackfish SQL Owed := 0 else Owed := Decimal(P1.Value); Owed := Owed + Amount; Command.Parameters.Clear; Command.CommandText := 'SELECT CREDIT INTO ? FROM CUSTOMER WHERE CUST_ID=?'; P1 := Command.Parameters.Add('P1', DbType.Decimal); P2 := Command.Parameters.Add('P2', DbType.Int32); P1.Direction := ParameterDirection.Output; P2.Value := CustId; Command.ExecuteNonQuery; Credit := Decimal(P1.Value); if Owed > Credit then raise Exception.Create('Customer doesn''t have that much credit'); Command.Parameters.Clear; Command.CommandText := 'UPDATE ITEMS SET STOCK=STOCK-? WHERE ITEM_ID=?'; P1 := Command.Parameters.Add('P1', DbType.Int32); P2 := Command.Parameters.Add('P2', DbType.Int32); P1.Value := Quantity; P2.Value := ItemId; Command.ExecuteNonQuery; 7 Command.Parameters.Clear; Command.CommandText := 'INSERT INTO ORDERS (CUST_ID, ITEM_ID, QUANTITY, SALE_AMOUNT) '+ 'VALUES (?, ?, ?, ?)'; P1 := Command.Parameters.Add('P1', DbType.Int32); P2 := Command.Parameters.Add('P2', DbType.Int32); P3 := Command.Parameters.Add('P3', DbType.Int32); P4 := Command.Parameters.Add('P4', DbType.Decimal); P1.Value := CustId; P2.Value := ItemId; P3.Value := Quantity; P4.Value := Amount; Command.ExecuteNonQuery; Command.Free; end; end. Schritt 2: Assembly erstellen und es für den Blackfish SQL-Server-Prozess zur Verfügung stellen. Nach Fertigstellung des Codes für die gespeicherte Prozedur: 1. Erstellen Sie eine Assembly-DLL (beispielsweise Procs.dll), die die Klasse MyClass aus Schritt 1 enthält. 2. Kopieren Sie das Assembly für das Deployment in das Unterverzeichnis, in dem sich die ausführbare Datei für den Blackfish SQL-Server (BSQLServer.exe) befindet. 46 7 7 Blackfish SQL Schritt 3: Erstellen Sie die Bindung eines SQL-Bezeichners für das Klassen-Member. Jetzt, da der Code ausgeführt werden kann, muss die Blackfish SQL-Datenbank über das Klassen-Member unterrichtet werden, das von SQL aufgerufen werden kann. Starten Sie hierzu DataExporer und geben Sie eine CREATE METHOD-Anweisung aus: CREATE METHOD ADD_ORDER AS 'MyProcs::SampleStoredProcedures.TMyClass.AddOrder'; MyProcs ist der Name des Pakets. Der Methodenname ist voll qualifiziert (enthält Unit-Name und Klassenname). Führen Sie die gespeicherte Prozedur ADD_ORDER mithilfe einer Delphi-Konsolen-Anwendung aus: unit MyCompany; interface implementation uses System.Data; type TSomething = class public procedure AddOrder( Connection: DbConnection; CustId: Integer; ItemId: Integer; Quantity: Integer); end; { Assume: Connection: CustId: ItemId: Quantity: } ist ist ist ist eine gültige Blackfish SQL-Verbindung. ein Kunde in der CUSTOMER-Tabelle. ein Produkt in der ITEMS-Tabelle. die Menge dieses bestellten Produkts. 7 procedure TSomething.AddOrder( Connection: DbConnection; CustId: Integer; ItemId: Integer; Quantity: Integer); var Command: DbCommand; P1, P2, P3: DbParameter; begin Command := con.CreateCommand; Command.CommandText := 'ADD_ORDER'; Command.CommandType := CommandType.StoredProcedure; P1 := Command.Parameters.Add('custId', DbType.Int32); P2 := Command.Parameters.Add('itemId', DbType.Int32); P3 := Command.Parameters.Add('quantity', DbType.Int32); P1.Value := CustId; P2.Value := ItemId; P3.Value := Quantity; Command.ExecuteNonQuery; Command.Free; end; end. Wenn TSomeThing.AddOrder in der Client-Anwendung aufgerufen wird, ruft diese ihrerseits die gespeicherte Prozedur ADD_ORDER auf, die für die Ausführung von TMyClass.AddOrder im Blackfish SQL-Server-Prozess sorgt. Durch den Aufruf von TMyClass.AddOrder durch eine gespeicherte Prozedur muss nur eine Anweisung über eine Remote-Verbindung ausgeführt werden. Die fünf Anweisungen, die von TMyClass.AddOrder ausgeführt werden, werden prozessintern vom Blackfish SQL-Server mithilfe einer lokalen Verbindung ausgeführt. 47 Blackfish SQL 7 Beachten Sie, dass die Anwendung keine Verbindungsinstanz an den Aufruf der gespeicherten Prozedur ADD_ORDER übergibt. Nur die tatsächlichen logischen Parameter werden übergeben. Blackfish SQL generiert ein implizites Verbindungsobjekt, wenn es eine gespeicherte Prozedur oder benutzerdefinierte Funktion findet, wobei das erste Argument eine System.Data.IDbConnection-Instanz sein muss. Ausgabeparameter und DBNull-Werte behandeln Die Delphi-Sprache unterstützt Ausgabeparameter und Referenzparameter. Die Blackfish SQL-Datenbank erkennt diese Parametertypen und behandelt sie entsprechend. NULL-Werte in einer Datenbank erfordern eine spezielle Verarbeitung. System.String kann vom NULL-Wert behandelt werden. Für alle anderen Typen muss der formale Parametertyp in TObject geändert werden, da NULL kein gültiger Wert für einen .NET-ValueType ist. Wenn der formale Parameter ein TObject-Typ ist, wird der Wert von System.DBNull für einen Datenbank-NULL-Wert verwendet. Blackfish SQL akzeptiert auch Typen, die NULL sein können, in gespeicherten Prozeduren, die in C# geschrieben sind (beispielsweise, int). Beispiele: Beispiel einer gespeicherten Prozedur mit einem INOUT-Parameter; NULL-Werte werden ignoriert: class procedure TMyClass.AddFive(ref Param: Integer); begin Param := Param + 5; end; Beispiel einer gespeicherten Prozedur mit einem INOUT-Parameter; NULL-Werte werden als NULL-Werte beibehalten: class procedure TMyClass.AddFour(ref Param: TObject); begin if Param <> nil then Param := TObject(Integer(Param) + 4); end; 7 Verwendung: procedure TryAdding(Connection: DbConnection); var Command: DbCommand; begin Command := Connection.CreateCommand; Command.CommandText := 'ADD_FIVE'; Command.CommandType := CommandType.StoredProcedure; P1 := Command.Parameters.Add('param', DbType.Int32); P1.Direction := ParameterDirection.InputOutput; P1.Value = 17; Command.ExecuteNonQuery; if 22 <> Integer(P1.Value) then raise Exception.Create('Wrong result'); Command.Parameters.Clear; Command.CommandText := 'ADD_FOUR'; Command.CommandType := CommandType.StoredProcedure; P1 := Command.Parameters.Add('param', DbType.Int32); P1.Direction := ParameterDirection.InputOutput; P1.Value = 17; Command.ExecuteNonQuery; if 21 <> Integer(P1.Value) then raise Exception.Create('Wrong result'); P1.Value = DBNull.Value; Command.ExecuteNonQuery; if DbNull.Value <> P1.Value then 48 7 Blackfish SQL raise Exception.Create('Wrong result'); Command.Free; end; Die obige Implementierung von AddFour verwendet eine TObject-Wrapper-Klasse für Ganzzahlen. Dies ermöglicht dem Entwickler von addFour, die von Blackfish SQL übergebenen NULL-Werte zu erkennen und einen Ausgabeparameter auf NULL zu setzen, damit er von Blackfish SQL erkannt wird. Im Gegensatz dazu kann in einer Implementierung für AddFive nicht ermittelt werden, ob ein Parameter NULL war, und es ist auch nicht möglich, das Ergebnis des Ausgabeparameters auf NULL zu setzen. SQL für die Blackfish SQL-Datenbank erweitern Wenn aus irgendeinem Grund ein Operator (beispielsweise: ein bitweiser AND-Operator) für eine where-Klausel benötigt wird und Blackfish SQL diesen nicht anbietet, können Sie in Delphi, Visual Basic, C# oder C++ einen solchen Operator erstellen und ihn als benutzerdefinierte Funktion aufrufen. Verwenden Sie jedoch diese Funktion mit Vorsicht, da Blackfish SQL den Zweck einer solchen Funktion nicht erkennt und nicht in der Lage ist, Indizes zu verwenden, um diesen Teil der Abfrage zu beschleunigen. Beachten Sie das bereits zuvor dargestellte UDF-Beispiel, das die benutzerdefinierte Funktion MAX_VALUE enthält: 'SELECT * FROM PEOPLE WHERE MAX_VALUE(HEIGHT,5*WIDTH) < ?' Diese Abfrage entspricht der folgenden Abfrage: 'SELECT * FROM PEOPLE WHERE HEIGHT < ? AND 5*WIDTH < ?' wobei der gleiche Wert für beide Parametermarkierungen gegeben ist. Diese SQL-Anweisung führt zum gleichen Ergebnis, da die Implementierung von MAX_VALUE bekannt ist. Blackfish SQL kann jedoch nur Indizes verwenden, die für die HEIGHT- und WIDTH-Spalte bei der zweiten Abfrage verfügbar sind. Wenn es derartige Indizes nicht gäbe, wäre die Leistung der zwei Abfragen etwa gleich. Der Vorteil einer benutzerdefinierten Funktion tritt zutage, wenn die Funktionalität noch nicht in Blackfish SQL vorhanden ist (beispielsweise: ein bitweiser AND-Operator). Gespeicherte .NET-Prozeduren debuggen So debuggen Sie gespeicherte .NET-Prozeduren: • Wenn das Protokoll in Bearbeitung oder nicht gesetzt ist • Wenn das Protokoll TCP ist Gespeicherte Prozeduren debuggen, wenn das Protokoll "In-process" oder nicht eingestellt ist So debuggen Sie gespeicherte Prozeduren, wenn das Protokoll "In-process" oder nicht eingestellt ist: 1. Erstellen Sie ein Projekt, das zum Debuggen verwendet werden kann. Erstellen Sie mit Ihrer bevorzugten IDE ein Projekt, das den Client-Code der Anwendung, die gespeicherten Prozeduren und eine Referenz auf die Bibliothek Borland.Data.BlackfishSQL.LocalClient.dll enthält. 2. Fügen Sie Haltepunkte in die gespeicherten Prozeduren ein. Der Debugger behandelt die gespeicherten Prozeduren genauso wie den Client-Code. Gespeicherte Prozeduren debuggen, wenn das Protokoll TCP ist So debuggen Sie gespeicherte Prozeduren, wenn das Protokoll TCP ist: Wenn Ihre IDE das Remote-Debuggen unterstützt: Delphi ist in der Lage, eine Verbindung zum Blackfish SQL-Server-Prozess herzustellen. 49 7 Blackfish SQL 7 1. Compilieren Sie die gespeicherte Prozeduren mit Debug-Informationen. 2. Kopieren Sie das Assembly in das bin-Verzeichnis von Blackfish SQL. 3. Starten Sie die Client-Anwendung im Debugger und stellen Sie eine Verbindung zum Serverprozess her. 4. Fügen Sie Haltepunkte in die gespeicherten Prozeduren ein. Der Debugger behandelt die gespeicherten Prozeduren genauso wie den Client-Code. Wenn Ihre IDE das Remote-Debuggen nicht unterstützt: 1. Erstellen Sie ein Projekt, das zum Debuggen verwendet werden kann. Richten Sie das Projekt so ein, dass ein direktes Debuggen des Servers möglich ist. 2. Erstellen Sie eine ausführbare Datei mit dem Namen Borland.Data.DataStore.DataStoreServer.StartDefaultServer. 3. Fügen Sie einen Haltepunkt in die gespeicherten Prozeduren ein. 4. Starten Sie den separaten Client-Prozess. Eine gespeicherte Prozedur verwenden, um einen ADO.NET-IDataReader zu erzeugen Eine gespeicherte Prozedur kann einen ADO.NET-DbDataReader erzeugen, indem sie einfach einen DbDataReader zurückliefert. Beispiel class function GetRiskyCustomers( Connection: DbConnection; Credit: Decimal credit): DbDataReader; var Command: DbCommand; P1: DbParameter; begin Command := Connection.CreateCommand; Command.CommandText := 'SELECT NAME FROM CUSTOMER WHERE CREDIT > ? '; P1 := Command.Parameters.Add('param', DbType.Decimal); P1.Value := Credit; Result := Command.ExecuteReader; end; 7 Beachten Sie, dass das command-Objekt am Ende der Methode nicht freigegeben wird. Würde es freigegeben, würde es DbDataReader implizit schließen, was dazu führen würde, dass die gespeicherte Prozedur keine Daten zurückgeben würde. Stattdessen schließt Blackfish SQL "command" implizit, nachdem die gespeicherte Prozedur aufgerufen wurde. Die gespeicherte Prozedur GetRiskyCustomers kann in ADO wie folgt verwendet werden: function GetRiskyCustomers( Connection: DbConnection): ArrayList; var Command: DbCommand; Reader: DbReader; List: ArrayList; begin List := ArrayList.Create; Command := Connection.CreateCommand; Command.CommandText := 'GETRISKYCUST'; Command.CommandType := CommandType.StoredProcedure; P1 := Command.Parameters.Add('Credit', DbType.Decimal); P1.Value := 2000; Reader := Command.ExecuteReader; while Reader.Read do List.Add(Reader.GetString(0)); Command.Free; Result := List; end; 50 7 Blackfish SQL Gespeicherte Prozeduren für die Java-Plattform erstellen Dieser Abschnitt bietet ausführliche Informationen zum Erstellen von gespeicherten Prozeduren für Blackfish SQL und von benutzerdefinierten Funktionen für die Java-Plattform. Eine gespeicherte Prozedur für eine Blackfish SQL-Datenbank erstellen Gespeicherte Prozeduren und benutzerdefinierte Funktionen für Blackfish SQL für Java müssen in Java geschrieben sein. Compilierte Java-Klassen für gespeicherte Prozeduren und benutzerdefinierte Funktionen müssen zum Klassenpfad (CLASSPATH) des Blackfish SQL-Serverprozesses hinzugefügt werden, um verwendet werden zu können. Der Datenbank-Administrator kann dadurch in gewissem Maß steuern, welcher Code hinzugefügt wird. Es besteht die Möglichkeit, nur Public static-Methoden in Public-Klassen verfügbar zu machen. Sie können den Klassenpfad für die Blackfish SQL-Tools aktualisieren, indem Sie die Klassen zum Verzeichnis <jds_home>/lib/storedproc hinzufügen. • Wenn die gespeicherte Prozedur aus einer .jar-Datei besteht, speichern Sie die JAR-Datei unter <jds_home>/storedproc/lib/jars. • Wenn die gespeicherte Prozedur aus Klassendateien besteht, speichern Sie die Klassendateien unter <jds_home>/storedproc/classes. Wenn die Datei Ihrer gespeicherten Prozedur beispielsweise com.acme.MyProc ist, würden Sie diese wie folgt speichern: c:<jds_home>/lib/storedproc/classes/com/acme/MyProc.class Gespeicherte Prozeduren oder benutzerdefinierte Funktionen für eine SQL-Engine verfügbar machen Nachdem Sie eine gespeicherte Prozedur oder eine benutzerdefinierte Funktion geschrieben und zum Klassenpfad (CLASSPATH) des Blackfish SQL-Serverprozesses hinzugefügt haben, weisen Sie ihr einen Methodennamen zu. Verwenden Sie dazu die folgende SQL-Syntax: CREATE JAVA_METHOD <Methodenname> AS <Methodendefinitionsstring> <method-name> ist ein SQL-Bezeichner, z. B. INCREASE_SALARY, und <method-definition-string> ist ein String mit einem voll qualifizierten Methodennamen. Beispiel: com.mycompany.util.MyClass.increaseSalary Gespeicherte Prozeduren oder benutzerdefinierte Funktionen können mithilfe des folgenden Befehls aus einer Datenbank entfernt werden: DROP JAVA_METHOD <Methodenname> Methoden können verwendet werden, sobald sie erstellt worden sind. Das nächste Beispiel verdeutlicht, wie eine benutzerdefinierte Funktion (UDF) definiert und aufgerufen wird. Beispiel für eine benutzerdefinierte Funktion In diesem Beispiel wird eine Methode definiert, die das erste Leerzeichen nach einem bestimmten Index im String sucht. Der erste SQL-Baustein definiert die benutzerdefinierte Funktion. Der zweite Baustein zeigt die Verwendung der Funktion an einem Beispiel. Angenommen, TABLE1 verfügt über zwei VARCHAR-Spalten: FIRST_NAME und LAST_NAME. Die CHAR_LENGTH-Funktion ist eine integrierte SQL-Funktion. package com.mycompany.util; public class MyClass { public static int findNextSpace(String str, int start) { return str.indexOf(' ',start); } } CREATE JAVA_METHOD FIND_NEXT_SPACE AS 51 7 Blackfish SQL 7 'com.mycompany.util.MyClass.findNextSpace'; SELECT * FROM TABLE1 WHERE FIND_NEXT_SPACE(FIRST_NAME, CHAR_LENGTH(LAST_NAME)) < 0; Eingabeparameter Beim Aufrufen einer Java-Methode wird eine abschließende Typenüberprüfung der Parameter durchgeführt. Numerische Typen werden ggf. in einen höheren Typ umgewandelt, damit sie den Parametertypen von Java-Methoden entsprechen. Die Reihenfolge numerischer Typen für Java-Typen ist: 1. double oder Double 2. float oder Float 3. java.math.BigDecimal 4. long oder Long 5. int oder Integer 6. short oder Short 7. byte oder Byte Andere, von Java erkannte Typen sind: • boolean oder Boolean • String • java.sql.Date • java.sql.Time 7 • java.sql.Timestamp • byte[] • java.io.InputStream Beachten Sie, dass wenn Sie NULL-Werte an Java-Methoden übergeben, Sie keine primitiven Datentypen verwenden können, z. B. short oder double. Verwenden Sie stattdessen die entsprechenden Kapselungsklassen (Short, Double). SQL-NULL-Werte werden als Java-null-Werte übergeben. Wenn eine Java-Methode über einen Parameter oder ein Array verfügt, der bzw. das nicht zu den in der Tabelle aufgelisteten Typen gehört, wird er bzw. es als SQL-OBJECT-Typ behandelt. Ausgabeparameter Wenn ein Java-Methodenparameter ein Array der erkannten Eingabetypen ist (außer byte[]), wird ein Ausgabeparameter erwartet. Blackfish SQL gibt ein Array der Länge 1 (Eins) an den Methodenaufruf weiter. Daraufhin sollte die Methode das erste Element im Array mit dem Ausgabewert füllen. Die erkannten Java-Typen für Ausgabeparameter sind: • double[] oder Double[] • float[] oder Float[] • java.math.BigDecimal[] • long[] oder Long[] • int[] oder Integer[] • short[] oder Short[] • Byte[] (aber nicht byte[], da dies an sich ein erkannter Eingabeparameter ist) • boolean[] oder Boolean[] 52 7 Blackfish SQL • String[] • java.sql.Date[] • java.sql.Time[] • java.sql.Timestamp[] • byte[][] • java.io.InputStream[] Ausgabeparameter können in SQL nur an Variablenmarker gebunden werden. Alle Ausgabeparameter sind in der Regel INOUT-Parameter, da Werte, die vor dem Ausführen einer Anweisung festgelegt werden, an die Java-Methode übergeben werden. Wenn kein Wert festgelegt wird, ist der Anfangswert beliebig. Wenn Parameter einen SQL-NULL-Wert ausgeben können (oder über einen gültigen NULL-Input verfügen), verwenden Sie statt der primitiven Datentypen die Kapselungsklassen. Beispiel package com.mycompany.util; public class MyClass { public static void max(int i1, int i2, int i3, int result[]) { result[0] = Math.max(i1, Math.max(i2,i3)); } } CREATE JAVA_METHOD MAX AS 'com.mycompany.util.MyClass.max'; CALL MAX(1,2,3,?); Die CALL-Anweisung muss mit einer CallableStatement-Anweisung vorbereitet werden, um einen Ausgabewert zu erhalten. Informationen zur Verwendung von java.sql.CallableStatement finden Sie in der JDBC-Dokumentation. Beachten Sie die Zuweisung von result[0] in der Java-Methode. Das an die Methode übergebene Array besteht aus genau einem Element. Implizite Verbindungsparameter Wenn der erste Parameter einer Java-Methode vom Typ java.sql.Connection ist, übergibt Blackfish SQL ein Verbindungsobjekt, das den transaktionalen Verbindungsinhalt freigibt, der zum Aufrufen der gespeicherten Prozedur verwendet wird. Dieses Verbindungsobjekt kann zum Ausführen von SQL-Anweisungen mithilfe der JDBC-API verwendet werden. Übergeben Sie mit diesem Parameter keine Werte: diese Aufgabe übernimmt JDataStore. Beispiel package com.mycompany.util; public class MyClass { public static void increaseSalary(java.sql.Connection con, java.math.BigDecimal amount) {java.sql.PreparedStatement stmt = con.prepareStatement("UPDATE EMPLOYEE SET SALARY=SALARY+?"); stmt.setBigDecimal(1,amount); stmt.executeUpdate(); stmt.close(); } } CREATE JAVA_METHOD INCREASE_SALARY AS 'com.mycompany.util.MyClass.increaseSalary'; CALL INCREASE_SALARY(20000.00); Hinweis: • INCREASE_SALARY erfordert nur einen Parameter: den Betrag, um den das Gehalt erhöht werden soll. Die entsprechende Java-Methode verfügt über zwei Parameter. 53 7 Blackfish SQL 7 • Rufen Sie commit(), rollback, setAutoCommit(), oder close() nicht für das Verbindungsobjekt auf, das an gespeicherte Prozeduren übergeben wird. Es ist nicht empfehlenswert, diese Funktion für benutzerdefinierte Funktionen zu verwenden, da dies die Leistung beeinträchtigt. Gespeicherte Prozeduren und JDBC-ResultSets Eine gespeicherte Java-Prozedur kann auf dem Client zu einem ResultSet führen, wenn entweder ein ResultSet oder ein DataExpress-DataSet von der Java-Implementierung der gespeicherten Prozedur zurückgegeben wird. Das DataSet wird automatisch in ein ResultSet für den Benutzer der gespeicherte Prozedur konvertiert. Beispiel In diesem Beispiel wird ein ResultSet zurückgegeben: package com.mycompany.util; public class MyClass { public static void getMarriedEmployees(java.sql.Connection con) java.sql.Statement stmt = con.getStatement(); java.sql.ResultSet rset = stmt.executeQuery("SELECT ID, NAME FROM EMPLOYEE WHERE SPOUSE IS NOT NULL"); return rset; } Hinweis: Schließen Sie die stmt-Anweisung nicht. Diese Anweisung wird implizit geschlossen. Beispiel Im folgenden Beispiel wird ein DataSet zurückgegeben, das automatisch in ein "ResultSet" konvertiert wird. 7 package com.mycompany.util; public class MyClass { public static void getMarriedEmployees() com.borland.dx.dataset.DataSet dataSet = getDataSetFromSomeWhere(); return dataSet; } Hinweis: Schließen Sie die stmt-Anweisung nicht. Diese Anweisung wird implizit geschlossen. Beispiel Registrieren Sie die vorherigen Beispiele wie folgt und rufen Sie sie auf: java.sql.Statement stmt = connection.getStatement(); stmt.executeUpdate("CREATE JAVA_METHOD GET_MARRIED_EMPLOYEES AS "+ "'com.mycompany.util.MyClass.getMarriedEmployees'"); java.sql.ResultSet rset = stmt.executeQuery("CALL GET_MARRIED_EMPLOYEES()"); int id = rset.getInt(1); String name = rset.getString(2); Überladene Methodensignaturen Java-Methoden können überladen sein, um einen Verlust der numerischen Genauigkeit zu vermeiden. Beispiel package com.mycompany.util; public class MyClass { public static int abs(int p) { return Math.abs(p); } 54 7 Blackfish SQL public static long abs(long p) { return Math.abs(p); } public static BigDecimal abs(java.math.BigDecimal p) { return p.abs(); } public static double abs(double p) { return Math.abs(p); } } CREATE JAVA_METHOD ABS_NUMBER AS 'com.mycompany.util.MyClass.abs'; SELECT * FROM TABLE1 WHERE ABS(NUMBER1) = 2.1434; Die überladene Methode abs wird in der SQL-Engine nur einmal registriert. Was würde passieren, wenn die abs-Methode, der ein BigDecimal übergeben wird, nicht implementiert würde? Wenn NUMBER1 ein NUMERIC-Wert mit Nachkommastellen ist, wird die abs-Methode aufgerufen, der ein double-Wert übergeben werden muss. Dabei kann es zu einem Verlust der Genauigkeit kommen, wenn die Zahl von einem BigDecimal in einen double-Wert konvertiert wird. Zuordnung von Rückgabetypen Der Rückgabewert der Methode wird einem entsprechenden SQL-Typ zugeordnet. Die Zuweisungstabelle sieht folgendermaßen aus: Rückgabetyp einer Methode Blackfish SQL - SQL-Typ byte oder Byte SMALLINT short oder Short SMALLINT int oder Integer INT long oder Long BIGINT java.math.BigDecimal DECIMAL float oder Float REAL double oder Double DOUBLE String VARCHAR boolean oder Boolean BOOLEAN 7 java.io.InputStream (Von java.io.InputStream abgeleitete Typen werden ebenfalls als INPUTSTREAM INPUTSTREAM behandelt) java.sql.Date DATE java.sql.Time TIME java.sql.Timestamp TIMESTAMP Alle anderen Typen: OBJECT Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) 55 Blackfish SQL Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( 7 56 see page 141) see page 137) 7 8 Blackfish SQL 8 Trigger in Blackfish SQL-Tabellen verwenden In diesem Kapitel werden Trigger und Blackfish SQL-Tabellen erläutert. • Allgemeines zu Triggern • Trigger anzeigen • Trigger in Blackfish SQL für Windows-Datenbanken erstellen • Trigger in Blackfish SQL für Java-Datenbanken erstellen Allgemeines zu Triggern Sie können für eine Blackfish SQL-Tabelle Trigger auf Zeilenebene erstellen. In Blackfish SQL für Java können Sie diese Trigger in Java implementieren. In Blackfish SQL für Windows können Sie diese Trigger in Delphi, C# oder VB.NET implementieren. Alle Trigger-.Methoden müssen als "static" deklariert werden und haben nur einen Parameter des Typs TriggerContext. Die Klasse TriggerContext ist semantisch identisch in Blackfish SQL für Java und Blackfish SQL für Windows. Es bestehen allerdings auf den beiden Plattformen Unterschiede in der Syntax. Auf der Windows-Plattform befindet sich die Klasse TriggerContext im Namespace Borland.Data.DataStore. Auf der Java-Plattform befindet sich die Klasse TriggerContext im Package com.borland.datastore. Der Trigger-Kontext dient zum Zugriff auf: • Ein Verbindungsobjekt • Die neue Zeile bei Insert- und Update-Triggern • Die alte Zeile bei Update- und Delete-Triggern Dabei gelten folgende Regeln: • Neue Zeilenwerte werden mit einem BEFORE UPDATE- oder einem BEFORE INSERT-Trigger geändert. • Alte Zeilenwerte können nicht geändert werden. • Fremdschlüssel- und Primärschlüsselbeschränkungen werden nach BEFORE-Triggern angewendet. • AFTER-Trigger werden nach Abschluss der Operation aufgerufen. Dazu gehört auch die erfolgreichen Aktivierung von Fremdschlüssel- und Primärschlüsselbeschränkungen. • Die Trigger-Implementierung sollte DML-Operationen vermeiden, die auf dieselbe Tabelle zugreifen. Dies kann nämlich zu 57 8 Blackfish SQL 8 einer endlosen Rekursion führen. • Gibt es mehrere Trigger desselben Typs für dieselbe Tabelle, entspricht die Aufrufreihenfolge der Trigger der Reihenfolge ihrer Erstellung. • Commit- und Rollback-Operationen werden bei der Ausführung des Triggers ignoriert, wenn innerhalb des Triggers eine Exception ausgegeben wird. Die Änderungen, die bereits durch die Anweisung veranlasst wurden, aufgrund der der Trigger ausgelöst wurde, werden rückgängig gemacht. Die Anforderungen für das Deployment von Anwendungen mit Trigger-Implementierungen sind für gespeicherte Prozeduren und Trigger identisch. Trigger anzeigen Um Trigger anzuzeigen, die für eine Tabelle erstellt wurden, rufen Sie die gespeicherte Prozedur DB_ADMIN.GET_TRIGGERS auf. Eine ausführliche Beschreibung finden Sie unter Gespeicherte Prozeduren - Referenz. Trigger in Blackfish SQL für Windows-Datenbanken erstellen Mit der Anweisung CREATE TRIGGER erstellen Sie einen Trigger in einer Blackfish SQL für Windows-Datenbank. In der SQL-Referenz finden Sie die Syntax und Beispiele für die Anweisung CREATE TRIGGER. Beispiel Diese Beispielanweisungen erstellen Trigger für die Customer-Klasse: CREATE TRIGGER BEFORE_INSERT_CUSTOMER BEFORE INSERT ON CUSTOMER AS OrderEntryAssembly::OrderEntry.Customer.beforeInsertTrigger CREATE TRIGGER BEFORE_UPDATE_CUSTOMER BEFORE UPDATE ON CUSTOMER AS OrderEntryAssembly::OrderEntry.Customer.beforeUpdateTrigger CREATE TRIGGER BEFORE_DELETE_CUSTOMER BEFORE DELETE ON CUSTOMER AS OrderEntryAssembly::OrderEntry.Customer.beforeDeleteTrigger CREATE TRIGGER AFTER_INSERT_CUSTOMER AFTER INSERT ON CUSTOMER AS OrderEntryAssembly::OrderEntry.Customer.afterInsertTrigger CREATE TRIGGER AFTER_UPDATE_CUSTOMER AFTER UPDATE ON CUSTOMER AS OrderEntryAssembly::OrderEntry.Customer.afterUpdateTrigger CREATE TRIGGER AFTER_DELETE_CUSTOMER AFTER DELETE ON CUSTOMER AS OrderEntryAssembly::OrderEntry.Customer.afterDeleteTrigger 8 Dies ist die Delphi-Implementierung des Customer-Klassen-Triggers: TCustomer = class class procedure class procedure class procedure class procedure class procedure class procedure end; BeforeInsertTrigger(Context: TriggerContext); static; BeforeUpdateTrigger(Context: TriggerContext); static; BeforeDeleteTrigger(Context: TriggerContext); static; AfterInsertTrigger(Context: TriggerContext); static; AfterUpdateTrigger(Context: TriggerContext); static; AfterDeleteTrigger(Context: TriggerContext); static; { TCustomer } class procedure TCustomer.AfterDeleteTrigger(Context: TriggerContext); begin HandleBeforeInsert(Context.GetNewRow()); end; class procedure TCustomer.AfterInsertTrigger(Context: TriggerContext); begin HandleBeforeUpdate(Context.GetOldRow(), Context.GetNewRow()); end; class procedure TCustomer.AfterUpdateTrigger(Context: TriggerContext); begin HandleBeforeDelete(Context.GetOldRow(), Context.GetNewRow()); end; class procedure TCustomer.BeforeDeleteTrigger(Context: TriggerContext); begin HandleAfterInsert(Context.getNewRow()); 58 8 Blackfish SQL end; class procedure TCustomer.BeforeInsertTrigger(Context: TriggerContext); begin HandleAfterUpdate(Context.getNewRow()); end; class procedure TCustomer.BeforeUpdateTrigger(Context: TriggerContext); begin HandleAfterDelete(Context.getNewRow()); end; Dies ist die C#-Implementierung des Customer-Klassen-Triggers: public class Customer { public static void BeforeInsertTrigger(TriggerContext Context) { HandleBeforeInsert(Context.GetNewRow()); } public static void BeforeUpdateTrigger(TriggerContext Context) { HandleBeforeUpdate(Context.GetOldRow(), Context.GetNewRow()); } public static void beforeDeleteTrigger(TriggerContext Context) { HandleBeforeDelete(Context.getNewRow()); } public static void afterInsertTrigger(TriggerContext Context) { HandleAfterInsert(Context.getNewRow()); } public static void afterUpdateTrigger(TriggerContext Context) { HandleAfterUpdate(Context.getNewRow()); } public static void afterDeleteTrigger(TriggerContext Context) { HandleAfterDelete(Context.getNewRow()); } } 8 Trigger in Blackfish SQL für Java-Datenbanken erstellen Mit der Anweisung CREATE TRIGGER erstellen Sie einen Trigger in einer Blackfish SQL für Java-Datenbank. In der SQL-Referenz finden Sie die Syntax und Beispiele für die Anweisung CREATE TRIGGER. Beispiele: Diese Beispielanweisungen erstellen Trigger für die Customer-Klasse: CREATE TRIGGER BEFORE_INSERT_CUSTOMER BEFORE INSERT ON CUSTOMER AS orderentry.Customer.beforeInsertTrigger CREATE TRIGGER BEFORE_UPDATE_CUSTOMER BEFORE UPDATE ON CUSTOMER AS orderentry.Customer.beforeUpdateTrigger CREATE TRIGGER BEFORE_DELETE_CUSTOMER BEFORE DELETE ON CUSTOMER AS orderentry.Customer.beforeDeleteTrigger CREATE TRIGGER AFTER_INSERT_CUSTOMER AFTER INSERT ON CUSTOMER AS orderentry.Customer.afterInsertTrigger CREATE TRIGGER AFTER_UPDATE_CUSTOMER AFTER UPDATE ON CUSTOMER AS orderentry.Customer.afterUpdateTrigger CREATE TRIGGER AFTER_DELETE_CUSTOMER AFTER DELETE ON CUSTOMER AS orderentry.Customer.afterDeleteTrigger Dies ist die Java-Implementierung des Customer-Klassen-Triggers: public class Customer { public static void beforeInsertTrigger(TriggerContext context) throws Exception { 59 Blackfish SQL 8 handleBeforeInsert(context.getNewRow()); } public static void beforeUpdateTrigger(TriggerContext context) throws Exception { handleBeforeUpdate(context.getOldRow(), context.getNewRow()); } public static void beforeDeleteTrigger(TriggerContext context) throws Exception { handleBeforeDelete(context.getOldRow(), context.getNewRow()); } public static void afterInsertTrigger(TriggerContext context) { handleAfterInsert(context.getNewRow()); } public static void afterUpdateTrigger(TriggerContext context) { handleAfterUpdate(context.getNewRow()); } public static void afterDeleteTrigger(TriggerContext context) { handleAfterDelete(context.getNewRow()); } } Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( 8 see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( 60 see page 141) see page 137) see page 43) 9 Blackfish SQL 9 Gespeicherte Prozeduren - Referenz Viele administrative Tasks werden von gespeicherten Prozeduren in der DB_ADMIN-Klasse unterstützt. Die Klasse DB_UTIL ermöglicht gespeicherte Prozeduren für numerische, String- und Datum/Zeit-Operationen. • Gespeicherte Prozeduren für DB_ADMIN • Gespeicherte Prozeduren für DB_UTIL: Numerische, String- und Datum/Zeit-Funktionen Gespeicherte Prozeduren für DB_ADMIN DB_ADMIN ist eine Gruppe gespeicherter Datenbankadministrationsaufgaben. Beispiel: Prozeduren (Stored Procedures) zum Ausführen einer Vielzahl von • Metadaten anzeigen • Automatisches Failover und inkrementelles Backup ändern • Datenbankeigenschaften verwalten • Tabellen überprüfen • Datenbankkopie für Backup-Zwecke 9 • Datenbankverschlüsselung • Datenbankpasswort ändern • Datenbankstatus anzeigen, z. B.: • Sperren • Statusprotokoll-IDs Diese Methoden können mithilfe der CALL-Anweisung per SQL aufgerufen werden. Sie können ohne einen METHOD-Alias aufgerufen werden, da Blackfish SQL die Methoden in DB_ADMIN als integrierte Methoden erkennt. DB_ADMIN-Methoden Nachfolgend finden Sie die Syntax und eine kurze Beschreibung jeder DB_ADMIN-Methode. ALTER_DATABASE ALTER_DATABASE(string properties) Ändert angegebene Datenbankeigenschaften. properties ist eine durch Komma getrennte Liste von Einstellungen für die Spalten in der DatabaseColumns-Klasse. Eine Eigenschaft wird folgendermaßen angegeben: <COLUMN_NAME>=<VALUE>. 61 Blackfish SQL 9 Weitere Informationen finden Sie in der Online-Hilfe zur DatabaseColumns-Klasse. ALTER_MIRROR ALTER_MIRROR(string mirrorName, string properties) Ändert eine vorhandene Spiegeldatenbankkonfiguration. mirrorName ist ein Wert aus der SysMirrors.NAME-Spalte. properties ist eine durch Komma getrennte Liste von Einstellungen für die Spalten in der SysMirrors-Klasse. Eine Eigenschaft wird folgendermaßen angegeben: <COLUMN_NAME>=<VALUE>. Weitere Informationen finden Sie in der Online-Hilfe zur SysMirrors-Klasse. ALTER_MIRROR_SCHEDULE ALTER_MIRROR_SCHEDULE(INT32 mirrorId, string properties) mirrorName Ändert ein vorhandenes Zeitplanelement der Spiegelung. ist ein Wert aus der SysMirrorSchedule.NAME-Spalte. properties ist eine durch Komma getrennte Liste von Einstellungen für die Spalten in der SysMirrorSchedule-Klasse. Eine Eigenschaft wird folgendermaßen angegeben: <COLUMN_NAME>=<VALUE>. Weitere Informationen finden Sie in der Online-Hilfe zur SysMirrorSchedule-Klasse. CHANGE_PASSWORD CHANGE_PASSWORD(string oldpassword, string newPassword) Ändert das Passwort für den derzeit verbundenen Benutzer. CLOSE_CONNECTION CLOSE_CONNECTION(INT32 connectionId, INT64 birthTimeMilliseconds) Schließt eine geöffnete Verbindung. Kann verwendet werden, um unerwünschte Verbindungen zu schließen. connectionId aus der Spalte ID, die von GET_CONNECTIONS zurückgegeben wird. birthTimeMilliseconds aus der Spalte BIRTH, die von GET_CONNECTIONS zurückgegeben wird. Gibt im Erfolgsfall true zurück Weitere Informationen dazu, wie Sie eine Tabelle der zu schließenden Verbindungen erhalten, finden Sie unter GET_CONNECTIONS. CLOSE_OTHER_CONNECTIONS CLOSE_OTHER_CONNECTIONS() Schließt alle anderen geöffneten Verbindungen. Für die Ausführung dieser Methode sind Administratorrechte erforderlich. 9 COPY_STREAMS COPY_STREAMS(string otherFilename, string adminUser, string adminPass, boolean doOverwrite, boolean doIgnoreErrors) Kopiert alle Tabellen und Indizes aus der aktuellen Datenbank in eine andere Datenbank. Die COPY_USERS-Methode sollte zuerst aufgerufen werden, wenn neue Benutzer zur Datenbank hinzugefügt wurden. otherFilename ist der Dateiname der Zieldatenbank. adminUser ist der Benutzer mit ADMIN-Berechtigung in der Zieldatenbank. adminPass ist das Passwort des Admin-Benutzers in der Zieldatenbank. overwrite erlaubt das Überschreiben der Tabellen. Wenn "false" zurückgegeben wird, wird ein Fehler verursacht. ignoreErrors verursacht Fehler, die beim Wiederherstellen einer beschädigten Datenbank ignoriert werden können. COPY_USERS COPY_USERS(string otherFilename, string adminUser, string adminPass, boolean doCopyEncryption, boolean replaceExistingUsers) Kopiert alle Benutzer aus der aktuellen Datenbank in die angegebene Datenbank. otherFilename ist der Dateiname der Zieldatenbank. adminUser ist der Benutzer mit ADMIN-Berechtigung in der Zieldatenbank. adminPass ist das Passwort des 62 9 Blackfish SQL Admin-Benutzers in der Zieldatenbank. copyEncryption. Wenn die aktuelle Datenbank verschlüsselt ist, wird die Zieldatenbank mit dem gleichen Schlüssel verschlüsselt. replaceExistingUsers. Falls "true", werden die vorhandenen Benutzer in der Zieldatenbank ersetzt. CREATE_MIRROR CREATE_MIRROR(string properties) Erstellt eine neue Spiegeldatenbank mit den bereitgestellten Konfigurationseigenschaften. properties ist eine durch Komma getrennte Liste von Einstellungen für die Spalten in der SysMirrors-Klasse. Eine Eigenschaft wird folgendermaßen angegeben: <COLUMN_NAME>=<VALUE>. Gibt eine eindeutige ID für die neue Spiegeldatenbank zurück. Weitere Informationen finden Sie in der Online-Hilfe zur SysMirrors-Klasse. CREATE_MIRROR_SCHEDULE CREATE_MIRROR_SCHEDULE(string mirrorName, string properties) Erstellt einen neuen Synchronisierungszeitplan für die Spiegeldatenbank. mirrorName. Der Name der Spiegeldatenbank, zu der das Spiegelungselement hinzugefügt wird. properties ist eine durch Komma getrennte Liste von Einstellungen für die Spalten in der SysMirrorSchedule-Tabelle. Eine Eigenschaft wird folgendermaßen angegeben: <COLUMN_NAME>=<VALUE>. Gibt einen eindeutigen INT64-Bezeichner für das neue Zeitplanelement zurück. Weitere Informationen finden Sie in der Online-Hilfe zur SysMirrorSchedule-Klasse. DROP_MIRROR DROP_MIRROR(string mirrorName) Entfernt eine vorhandene Spiegeldatenbankkonfiguration. mirrorName ist ein Wert aus der SysMirrors.NAME-Spalte. Weitere Informationen finden Sie in der Online-Hilfe zur SysMirrors-Klasse. DROP_MIRROR_SCHEDULE DROP_MIRROR_SCHEDULE(INT32 mirrorID) mirrorID Entfernt ein vorhandenes Zeitplanelement der Spiegeldatenbank. ist ein Wert aus SysMirrorSchedule.ID-Spalte Weitere Informationen finden Sie in der Online-Hilfe zur SysMirrorSchedule-Klasse. der ENCRYPT 9 ENCRYPT(string adminPassword, string masterKeySeed) Verschlüsselt eine leere Datenbank. adminPass ist das Passwort des Benutzers, der diesen Befehl ausführt. masterKeySeed eine zufällige Folge von 16 Zeichen, die intern als Master-Passwort verwendet wird. Nach der ersten Angabe braucht es für den Zugriff auf die Datenbank nicht mehr verwendet zu werden. Dies sollte eine zufällige Folge von Zeichen sein. GET_ALL_LICENCES GET_ALL_LICENCES( ) Gibt eine Ergebnistabelle ohne oder mit mehreren Zeilen aller Lizenzen aus, die gefunden wurden. Die Spalten für diese Ergebnistabelle sind in der LicenseColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur LicenseColumns-Klasse. GET_COLUMN_PRIVILEGES GET_COLUMN_PRIVILEGES(string catalogPattern, string schemaPattern, string tablePattern, string columnPattern) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, 63 Blackfish SQL 9 um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. columnPattern gibt das LIKE-Spaltensuchmuster an. null bedeutet, dass der Spaltenname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit Spaltenberechtigungen für die angegebenen Tabellen zurück. Die Spalten für diese Ergebnistabelle sind in der ColumnPrivilegeColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur ColumnPrivilegeColumns-Klasse. GET_COLUMNS GET_COLUMNS(string columnPattern) catalogPattern, string schemaPattern, string tablePattern, string catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. columnPattern gibt das LIKE-Spaltensuchmuster an. null bedeutet, dass der Spaltenname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit Metadaten für die Spalten der angegebenen Tabellen zurück. Die Spalten für diese Ergebnistabelle sind in der ColumnsColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur ColumnsColumns-Klasse. GET_CONNECTIONS GET_CONNECTIONS() Gibt eine Ergebnistabelle der geöffneten Verbindungen für die aktuelle Serververbindung zurück. Die Spalten für diese Ergebnistabelle sind in der ConColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur ConColumns-Klasse. GET_DATABASE_PRIVILEGES GET_DATABASE_PRIVILEGES(boolean forRoles) Wenn forRoles den Wert true hat, handelt es sich um eine Rolle, bei false um einen Benutzer. Gibt eine Ergebnistabelle mit Datenbankzugriffsrechten für jeden Benutzer oder jede Rolle unter Verwendung der folgenden Spalten zurück: 1. GRANTOR String => Person, die Zugriffsrechte erteilt 9 2. GRANTEE String => Empfänger der Zugriffsrechte 3. PRIVILEGE String => Name des Zugriffsrechts (STARTUP, ADMINISTRATOR, WRITE, CREATE, DROP, RENAME, CREATE_ROLES, CREATE_SCHEMAS) 4. IS_GRANTABLE String => YES, wenn der Empfänger anderen Benutzern Rechte gewähren kann; NO, falls dies nicht der Fall ist. GET_DATABASE_PRODUCT_NAME GET_DATABASE_PRODUCT_NAME() Gibt den Produktnamen des Servers als String zurück. GET_DATABASE_PRODUCT_VERSION GET_DATABASE_PRODUCT_VERSION() Gibt die Produktversion des Servers als String zurück. 64 9 Blackfish SQL GET_DATABASE_PROPS GET_DATABASE_PROPS() Gibt eine Ergebnistabelle mit den Eigenschaften für die aktuelle Datenbank zurück. Die Spalten für diese Ergebnistabelle sind in der DatabaseColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur DatabaseColumns-Klasse. GET_DATABASE_STATUS GET_DATABASE_STATUS() Gibt eine Ergebnistabelle mit einer Zeile mit Statusinformationen über die aktuelle Datenbank zurück. Die Spalten für diese Ergebnistabelle sind in der DatabaseStatusTable-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur DatabaseStatusTable-Klasse. GET_DATABASE_STATUS_LOG_FILTER GET_DATABASE_STATUS_LOG_FILTER() Gibt einen INT32-Filter zurück, mit dem gesteuert werden kann, welche Protokollierungsinformationen für alle aktuellen Datenbankverbindungen in der Statusprotokolldatei gespeichert werden sollen. Die Bit-Masken sind in der LogFilterCodes-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur LogFilterCodes-Klasse. GET_DATATYPES GET_DATATYPES() Gibt eine Ergebnistabelle mit einer Zeile für jeden unterstützten Datentyp auf dem Datenbank-Server zurück. Die Spalten für diese Ergebnistabelle sind in der DataTypesColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur DataTypesColumns-Klasse. GET_FOREIGN_KEYS GET_FOREIGN_KEYS(catalogPattern, schemaPattern, tablePattern) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit einer Zeile für jeden Fremdschlüssel in den angegebenen Tabellen zurück. Die Spalten für diese Ergebnistabelle sind in der ForeignKeyColumnsColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur ForeignKeyColumnsColumns-Klasse. GET_FOREIGN_KEY_COLUMNS GET_FOREIGN_KEY_COLUMNS(string catalogPattern, string schemaPattern, string tablePattern, string foreignKeyPattern, string primaryCatalogPattern, string primarySchemaPattern, string primaryTablePattern, string primaryIndexPattern) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. foreignKeyPattern gibt das LIKE-Fremdschlüsselsuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. primaryCatalogPattern gibt das LIKE-Primärkatalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. primarySchemaPattern gibt das LIKE-Primärschemasuchmuster an. null bedeutet, dass der primäre Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. primaryTablePattern gibt das LIKE-Primärtabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. primaryIndexPattern gibt das LIKE-Primärtabellenindexsuchmuster an. null bedeutet, dass der 65 9 Blackfish SQL 9 Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit einer Zeile für jedes Fremdschlüsselspaltenpaar in den angegebenen Tabellen zurück. Die Spalten für diese Ergebnistabelle sind in der ForeignKeyColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur ForeignKeyColumnns-Klasse. GET_INDEXES GET_INDEXES(string catalogPattern, string schemaPattern, string tablePattern) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit den Indizes für die angegebenen Tabellen zurück. Die Spalten für diese Ergebnistabelle sind in der IndexesColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur IndexesColumns-Klasse. GET_INDEX_COLUMNS GET_INDEX_COLUMNS(string indexPattern) catalogPattern, string schemaPattern, string tablePattern, string catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. columnPattern gibt das LIKE-Spaltensuchmuster an. null bedeutet, dass der Spaltenname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit den Spalteninformationen der angegebenenTabellen zurück. Die Spalten für diese Ergebnistabelle sind in der IndexColumnsColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur IndexColumnsColumns-Klasse. GET_KEYWORDS GET_KEYWORDS() Gibt eine Ergebnistabelle mit den reservierten Schlüsselwörter in dieser Datenbank zurück. GET_LICENSE GET_LICENSE() 9 Gibt eine Ergebnistabelle mit einer Zeile zurück, die Lizenzdaten für die beste gefundene Deployment-Lizenz enthält. Die Spalten für diese Ergebnistabelle sind in der LicenseColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur LicenseColumns-Klasse. GET_LICENSE_SEARCH_DIRS GET_LICENSE_SEARCH_DIRS() Gibt eine Ergebnistabelle mit einer Zeile für jedes Verzeichnis zurück, das nach Lizenzdateien durchsucht wird. GET_LOCKS GET_LOCKS() Stellt eine Ergebnistabelle aller zurzeit aktiven Tabellen- und Zeilensperrungen für alle Verbindungen zur aktuellen Datenbank zur Verfügung. Die Spalten für diese Ergebnistabelle sind in der LockColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur LockColumns-Klasse. 66 9 Blackfish SQL GET_MIRROR_ID GET_MIRROR_ID() Gibt die INT64-Spiegeldatenbank-ID der aktuellen Spiegeldatenbank zurück, wenn es sich um eine Spiegeldatenbank handelt. GET_MIRRORS GET_MIRRORS(mirrorName, checkStatus) name ist der Name der Spiegeldatenbank, null prüft alle Spiegeldatenbanken. checkStatus wird auf TRUE gesetzt, um zusätzliche Spalten zum Status der Spiegeldatenbank bereitzustellen. Für die Statusüberprüfung ist mehr Arbeit erforderlich, dafür bietet sie aber weitere Informationen zu einer Spiegeldatenbank. Gibt eine Ergebnistabelle mit einer Zeile für jede Spiegeldatenbank zurück. Die Spalten für diese Ergebnistabelle sind in der MirrorStatusColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur MirrorStatusColumns-Klasse. GET_NEWEST_STATUS_LOG_ID GET_NEWEST_STATUS_LOG_ID() Gibt die INT32-ID der aktuellsten Protokolldatei zurück, die mithilfe der GET_STATUS_LOG()-Methode abgerufen werden kann. GET_OLDEST_STATUS_LOG_ID GET_OLDEST_STATUS_LOG_ID() Gibt die INT32-ID der ältesten Protokolldatei zurück, die mithilfe der GET_STATUS_LOG()-Methode abgerufen werden kann. GET_PROCEDURES GET_PROCEDURES(string type) catalogPattern, string schemaPattern, string procedurePattern, string catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. procedurePattern gibt das LIKE Prozedursuchmuster an. null bedeutet, dass der Prozedurname nicht verwendet werden sollte, um die Suche einzugrenzen. procedureType ist ein Prozedurtyp und muss entweder PROCEDURE, FUNCTION oder null für beliebige Prozedurtypen sein. Gibt eine Ergebnistabelle mit den Metadaten für die bekannten gespeicherten Prozeduren zurück. Die Spalten für diese Ergebnistabelle sind in der ProcedureColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur ProcedureColumns-Klasse. GET_PROCEDURE_COLUMNS GET_PROCEDURE_COLUMNS(string string parameterPattern) catalogPattern, string schemaPattern, string procedurePattern, catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. procedureNamePattern gibt das LIKE Prozedursuchmuster an. null bedeutet, dass der Prozedurname nicht verwendet werden sollte, um die Suche einzugrenzen. columnNamePattern gibt das LIKE Spaltensuchmuster an. null bedeutet, dass der Spaltenname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit den Parametern für die angegebenen Prozeduren zurück. Die Spalten für diese Ergebnistabelle sind in der ProcedureParametersColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur ProcedureParametersColumns-Klasse. 67 9 Blackfish SQL 9 GET_PROCEDURE_PRIVILEGES GET_PROCEDURE_PRIVILEGES() Gibt eine Ergebnistabelle mit Beschreibungen der Zugriffsrechte für jede Prozedur zurück. Die Ergebnistabelle enthält die folgenden Spalten: 1. PROCEDURE_CAT String => Prozedurkatalog (ist immer null) 2. PROCEDURE_SCHEM String => Prozedurschema 3. PROCEDURE_NAME String => Prozedurname 4. GRANTOR String => Person, die Zugriffsrechte erteilt 5. GRANTEE String => Empfänger der Zugriffsrechte 6. PRIVILEGE String => Name des Zugriffsrechts (EXECUTE) 7. IS_GRANTABLE String => YES, wenn der Empfänger anderen Benutzern Rechte gewähren kann; NO, falls dies nicht der Fall ist. GET_ROLES GET_ROLES() Gibt eine Ergebnistabelle mit den Rollen in der Datenbank zurück. Die Spalten für diese Ergebnistabelle sind in der RolesColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur RolesColumns-Klasse. GET_ROLE_GRANTS GET_ROLE_GRANTS(boolean forRoles) Wenn forRoles den Wert true hat, handelt es sich um eine Rolle, bei false um einen Benutzer. Die Ergebnistabelle enthält die folgenden Spalten: 1. ROLE_NAME String => Name der gewährten Rolle 2. GRANTOR String => Person, der die Rolle vergibt 3. GRANTEE String => Empfänger der Rolle 4. IS_GRANTABLE String => YES, wenn der Empfänger anderen Benutzern Rechte gewähren kann; NO, falls dies nicht der Fall ist. 9 GET_SCHEMAS GET_SCHEMAS(string catalogPattern) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke Gibt eine Ergebnistabelle mit den Schemas in der Datenbank zurück. GET_STATUS_LOG_FILTER GET_STATUS_LOG_FILTER() Gibt den INT32-Filter zurück, der den Typ der Protokollierungsinformationen steuert, die im Statusprotokoll für diese Verbindung gespeichert werden sollen. Die Bit-Masken sind in der LogFilterCodes-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur LogFilterCodes-Klasse. GET_STATUS_LOG GET_STATUS_LOG(INT32 log_id, INT64 offset) 68 9 Blackfish SQL id ist die ID der abgerufenen Protokolldatei. offset ist der Offset in der Protokolldatei ab dem Beginn der Datei. Gibt das Statusprotokoll für die aktuellw Datenbank als Datenstrom zurück. GET_STATUS_LOGS GET_STATUS_LOGS() Gibt eine Ergebnistabelle mit der ID der vorhandenen Protokolle für diese Datenbank zurück. Die Spalten für diese Ergebnistabelle sind in der StatusLogColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur StatusLogColumns-Klasse. GET_TABLE_PRIVILEGES GET_TABLE_PRIVILEGES(string catalogPattern, string schemaPattern, string tablePattern) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit Berechtigungsbeschreibungen für die gewählten Tabellen zurück. Die Spalten für diese Ergebnistabelle sind in der TablePrivilegeColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur TablePrivilegeColumns-Klasse. GET_TABLES GET_TABLES(string catalogPattern, string schemaPattern, string tablePattern, string type) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. "types" ist eine durch Komma getrennte Liste von TABLE, VIEW, SYSTEM_TABLE oder null. Gibt eine Ergebnistabelle mit Metadaten für die angegebenen Tabellen zurück. Die Spalten für diese Ergebnistabelle sind in der TableColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur TableColumns-Klasse. GET_THIS_MIRROR GET_THIS_MIRROR(boolean checkStatus) checkStatus wird auf TRUE gesetzt, um zusätzliche Spalten zum Status der Spiegeldatenbank bereitzustellen. Wie GET_MIRRORS, außer dass Informationen nur für die Spiegeldatenbank, auf die diese Prozedur angewendet wird, zurückgegeben werden. Gibt eine Ergebnistabelle mit einer Zeile für diese Spiegeldatenbank zurück. Die Spalten für diese Ergebnistabelle sind in der MirrorStatusColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur MirrorStatusColumns-Klasse. GET_TRIGGERS GET_TRIGGERS(string catalogPattern, string schemaPattern, string tablePattern, string trigger) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. triggerPattern gibt das LIKE-Triggersuchmuster an. null bedeutet, dass der Triggername nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle der Trigger für die angegebenen Tabellen zurück. Die Ergebnistabelle enthält die folgenden Spalten: 1. TRIGGER_CAT String => Triggerkatalog (ist immer null) 2. TRIGGER_SCHEM String => Triggerschema 69 9 Blackfish SQL 9 3. TRIGGER_TABLE String => Triggertabelle 4. TRIGGER_TYPE String => Triggertyp 5. TRIGGER_METHOD String => Name der Triggermethode GET_USERS GET_USERS() Gibt eine Ergebnistabelle mit den Benutzern in der Datenbank zurück. GET_VIEWS GET_VIEWS(string catalogPattern, string schemaPattern, string view) catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. viewNamePattern gibt das LIKE-Ansichtsuchmuster an. null bedeutet, dass der Ansichtsname nicht verwendet werden sollte, um die Suche einzugrenzen. Gibt eine Ergebnistabelle mit den Definitionen für die angegebenen Ansichten zurück. Die Spalten für diese Ergebnistabelle sind in der ViewsColumns-Klasse definiert. Weitere Informationen finden Sie in der Online-Hilfe zur ViewsColumns-Klasse. SET_DATABASE_STATUS_LOG_FILTER SET_DATABASE_STATUS_LOG_FILTER(INT32 filter) Setzt den Filter, der den Typ der Protokollierungsinformationen steuert, die in der Statusprotokolldatei für alle aktuellen Datenbankverbindungen gespeichert werden sollen. SET_PRIMARY_MIRROR SET_PRIMARY_MIRROR(INT64 forceSwitch) txTerminationTimeout, boolean forceTransactionAbort, boolean Legt die aktuelle Spiegeldatenbank als primäre Spiegeldatenbank fest. txTerminationTimeout sind die Millisekunden, die gewartet wird, bis vorhandene Transaktionen beendet werden. forceTxTermination verursacht den Abbruch der vorhandenen Transaktionen, nachdem txTerminationTimeout Millisekunden vergangen sind. forceSwitch legt die aktuelle Spiegeldatenbank auch dann als primäre Spiegeldatenbank fest, wenn andere Spiegelungen nicht mit dieser Änderung synchronisiert werden können. 9 SET_STATUS_LOG_FILTER SET_STATUS_LOG_FILTER(INT32 filter) Setzt den INT32-Filter, der den Typ der Protokollierungsinformationen steuert, die in der Statusprotokolldatei für die aktuelle Verbindung gespeichert werden sollen. SYNCH_MIRROR SYNCH_MIRROR(string mirrorName) Aktualisiert den für mirrorName angegebenen Mirror unter Verwendung der aktuellsten Protokolldateien, falls erforderlich. VALIDATE_PRIMARY_MIRROR VALIDATE_PRIMARY_MIRROR() Validiert eine primäre Spiegeldatenbank, sodass Schreibtransaktionen auf sie angewendet werden können. 70 9 Blackfish SQL verify VERIFY(string catalogPattern, string schemaPattern, string tablePattern, INT32 displayOptions, INT32 errorCount, out INT32 errorsEncountered, out String output) Überprüft eine oder mehrere Tabellen in der Datenbank. catalogPattern gibt das LIKE-Katalogsuchmuster an. Nicht verwendet. Reserviert für zukünftige Verwendungszwecke. schemaPattern gibt das LIKE-Schemasuchmuster an. null bedeutet, dass der Schemaname nicht verwendet werden sollte, um die Suche einzugrenzen. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. displayOptions - Eine oder mehrere StreamVerifierDisplay-Bit-Einstellungen sind mittels OR verknüpft, wodurch der Verifizierer angewiesen wird, Statusmeldungen anzuzeigen, wenn der Datenstrom verifiziert ist. errorCount gibt die Anzahl der Fehler an, die ignoriert werden können, bevor eine Exception ausgelöst wird. errorsEncountered ist ein Ausgabeparameter, der die Anzahl der Fehler zurückgibt, die aufgetreten sind. output ist ein Ausgabeparameter, der verwendet werden kann, um einen String mit Diagnoseausgabe von diesem Verifizierer zurückzugeben. verify VERIFY(string tablePattern, INT32 errorsEncountered, out String output) displayOptions, INT32 errorCount, out INT32 Überprüft eine oder mehrere Tabellen in der Datenbank. tablePattern gibt das LIKE-Tabellensuchmuster an. null bedeutet, dass der Tabellenname nicht verwendet werden sollte, um die Suche einzugrenzen. displayOptions - Eine oder mehrere StreamVerifierDisplay-Bit-Einstellungen sind mittels OR verknüpft, wodurch der Verifizierer angewiesen wird, Fortschrittsmeldungen anzuzeigen, wenn der Datenstrom verifiziert ist. errorCount gibt die Anzahl der Fehler an, die ignoriert werden können, bevor eine Exception ausgelöst wird. errorsEncountered ist ein Ausgabeparameter, der die Anzahl der Fehler zurückgibt, die aufgetreten sind. output ist ein Ausgabeparameter, der verwendet werden kann, um einen String mit Diagnoseausgabe von diesem Verifizierer zurückzugeben. DB_UTIL: Numerische, String- und Datum/Zeit-Funktionen DB_UTIL besteht aus gespeicherten SQL-Prozeduren (SQL Stored Procedures) zum Ausführen numerischer, String- und Datum/Zeit-Operationen auf in Datenbanktabellen gespeicherten Daten. Diese Funktionen sind als benutzerdefinierte Java-Funktion in DB_UTIL implementiert. Beispiele Folgende Anweisung berechnet die Quadratwurzel der Spalte COL1: 9 SELECT DB_UTIL.SQRT(COL1) FROM TABLE1; Folgende Anweisung berechnet Zeitstempel, die dem Zeitstempel COL2 plus fünf Stunden entsprechen. SELECT DB_UTIL.TIMESTAMPADD('SQL_TSI_HOUR',5,COL2) FROM TABLE1; Numerische Funktionen ACOS ACOS(expression) Gibt den Arcuscosinus im Bogenmaß zurück. ASIN ASIN(expression) Gibt den Arcussinus im Bogenmaß zurück. 71 Blackfish SQL 9 ATAN ATAN(expression) Gibt den Arcustangens im Bogenmaß zurück. ATAN2 ATAN2(y, x) Gibt den Arcustangens des Quotienten der zwei Argumente zurück. Der zurückgegebene Winkel ist ein numerischer Wert im Bogenmaß zwischen PI und -PI und repräsentiert den Winkel im entgegengesetzten Uhrzeigersinn zwischen der positiven X-Achse und dem Punkt (x, y). Beachten Sie, dass der y-Wert zuerst übergeben wird. CEILING CEILING(expression) Gibt die kleinste Ganzzahl zurück, die größer gleich dem Argument ist. Der Rückgabewert hat denselben Datentyp wie der Input-Wert. COS COS(expression) Gibt den Cosinus eines Winkels zurück. COT COT(expression) Gibt den Cotangens eines Winkels zurück. DEGREES DEGREES(expression) Konvertiert einen Winkel im Bogenmaß in Grad. EXP 9 EXP(expression) Gibt den Exponentialwert von expression zurück. FLOOR FLOOR(expression) Gibt die größte Ganzzahl zurück, die kleiner gleich expression ist. Der Rückgabewert hat denselben Datentyp wie der Input-Wert. log LOG(expression) Gibt den natürlichen Logarithmus einer Zahl zurück. LOG10 LOG10(expression) Gibt den dekadischen Logarithmus (Basis 10) einer Zahl zurück. 72 9 Blackfish SQL MOD MOD(expression1, expression2) Gibt den Rest von expression1 dividiert durch expression2 zurück, wobei beide Ausdrücke Ganzzahlen des Typs SHORT, INT oder LONG sind. Der Rückgabewert hat denselben Datentyp wie der Input-Wert. PI PI() Gibt die Konstante PI zurück. POWER POWER(expression1, expression2) Gibt das Ergebnis von expression1 potenziert mit expression2 zurück. RADIANS RADIANS(expression) Konvertiert einen Winkel in Grad in Bogenmaß. RAND RAND() Generiert eine Zufallszahl als Fließkommawert. RAND RAND(expression) Generiert eine Zufallszahl als Fließkommawert mit expression als Startwert (Integer-Datentyp). ROUND ROUND(expression1, expression2) 9 Rundet expression1 auf expression2 Dezimalstellen. SIGN SIGN(expression) Gibt -1 zurück, wenn der Wert von expression negativ, 0, wenn expression 0, und 1, wenn expression positiv ist. Der Rückgabewert hat denselben Datentyp wie der Input-Wert. SIN SIN(expression) Gibt den Sinus eines Winkels im Bogenmaß zurück. SQRT SQRT(expression) Gibt die Quadratwurzel einer Zahl zurück. 73 Blackfish SQL 9 TAN TAN(expression) Gibt den Tangens eines Winkels im Bogenmaß zurück. TRUNCATE TRUNCATE(expression1, expression2) Kürzt expression1 um expression2 Dezimalstellen. String-Funktionen ASCII ASCII(string) Gibt eine Ganzzahl zurück, die für den ASCII-Wert des Zeichens in string steht, das sich am weitesten links befindet. TO_CHAR TO_CHAR(ascii_code) Gibt das char-Äquivalent des ASCII-Code-Arguments zurück. Difference DIFFERENCE(string1, string2) Gibt eine Ganzzahl zwischen 0 und 4 zurück, die angibt, wie viele der vier Zahlen, die von SOUNDEX für string1 zurückgegeben wurden, mit denen identisch sind, die für string2 zurückgegeben wurden. Ein Rückgabewert von 4 bedeutet, dass die SOUNDEX-Codes identisch sind. INSERT_STRING INSERT_STRING(string1, start, length, string2) Gibt einen Zeichen-String zurück, der gebildet wird durch Löschen von length Zeichen aus string1 beginnend bei start und durch Einfügen von string2 in string1 bei start. 9 LEFT_STRING LEFT_STRING(string, count) Gibt die count Zeichen von string zurück, die sich am weitesten links befinden. REPEAT REPEAT(string, count) Ein Zeichen-String, der geformt wird durch count-faches Wiederholen von string. REPLACE REPLACE (string1, string2, string3) Gibt einen Zeichen-String zurück, der geformt wird durch das Ersetzen aller Vorkommen von string2 in string1 durch string3. 74 9 Blackfish SQL RIGHT RIGHT_STRING(string, count) Gibt einen String zurück, der aus n (count) Zeichen von rechts aus string besteht. SOUNDEX SOUNDEX (string) Gibt einen String zurück, der den Klang von Wörtern repräsentiert. Der Inhalt des Strings hängt von der Datenquelle ab und kann beispielsweise ein vierstelliger SOUNDEX-Code, eine phonetische Darstellung der Wörter oder eine andere Form sein. SPACE SPACE(count) Gibt einen Zeichen-String zurück, der aus n (count) Leerzeichen besteht. Datums- und Zeitfunktionen DAYNAME DAYNAME(date) Gibt den Wochentag als String aus dem vorhandenen Datum zurück. DAYOFWEEK DAYOFWEEK(date) Gibt den Wochentag als Zahl zurück: 1=Sonntag, 7=Samstag. DAYOFYEAR DAYOFYEAR(date) Gibt den Tag des Jahres als Zahl zurück: 1=1. Januar. 9 MONTHNAME MONTHNAME(date) Gibt den Monatsnamen als String aus dem vorhandenen Datum zurück. QUARTER QUARTER(date) Gibt das Quartal als Zahl aus dem vorhandenen Datum zurück: 1=Januar bis März, 2=April bis Juni. TIMESTAMPADD TIMESTAMPADD(interval, count, timestamp) Gibt einen Zeitstempel zurück, der berechnet wird durch Hinzufügen einer Anzahl (count) Intervalle (interval) zu timestamp. interval kann eines der folgenden Intervalle sein und muss in einfache Anführungszeichen eingeschlossen werden: SQL_TSI_FRAC_SECOND, SQL_TSI_SECOND, SQL_TSI_MINUTE, SQL_TSI_HOUR, SQL_TSI_DAY, SQL_TSI_WEEK, SQL_TSI_MONTH, SQL_TSI_QUARTER oder SQL_TSI_YEAR. 75 Blackfish SQL 9 timestamp kann einer der folgenden SQL-Datentypen sein: DATE, TIME, TIMESTAMP. TIMESTAMPDIFF TIMESTAMPDIFF(interval, timestamp1, timestamp2) Gibt die Anzahl der Intervalle zurück, die timestamp2 größer ist als timestamp1. interval kann eines der folgenden Intervalle sein und muss in einfache Anführungszeichen eingeschlossen werden: SQL_TSI_FRAC_SECOND, SQL_TSI_SECOND, SQL_TSI_MINUTE, SQL_TSI_HOUR, SQL_TSI_DAY, SQL_TSI_WEEK, SQL_TSI_MONTH, SQL_TSI_QUARTER oder SQL_TSI_YEAR. timestamp1 und timestamp2 können einer der folgenden SQL-Datentypen sein: DATE, TIME, TIMESTAMP. WEEK WEEK(date) Gibt eine Ganzzahl von 1 bis 53 für die Woche des Jahres zurück. Sie wird aus dem Datum (date) ermittelt. 1=Erste Woche des Jahres. Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( SQL-Referenz ( see page 57) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( 9 Fehlersuche ( 76 see page 141) see page 137) see page 43) 10 Blackfish SQL 10 SQL-Referenz Die SQL-Referenz enthält folgende Themen: Datentypen Literale Schlüsselwörter Bezeichner Listensyntax Ausdrücke Prädikate Funktionen Tabellenausdrücke Anweisungen Anweisungen zur Datendefinition Anweisungen zur Transaktionssteuerung Anweisungen zur Datenmanipulation Sicherheitsanweisungen Escape-Sequenzen Escape-Funktionen ISQL Datentypen In SQL können Sie Datentypen anhand der Blackfish SQL-Namen oder durch Synonyme definieren, die besser in andere SQL-Dialekte portierbar sind. In der folgenden Tabelle werden die Blackfish SQL-SQL-Datentypen und ihre Java-Entsprechungen aufgelistet. Eine Beschreibung der einzelnen Datentypen finden Sie unter Administration von Blackfish SQL. Strings werden im UNICODE-Format gespeichert. Wenn ein String keine High-Bit-Zeichen enthält, werden die High-Byte nicht gespeichert und die Anzahl der Byte entspricht der Anzahl an Zeichen. In Sprachen mit Doppel-Byte-Zeichensatz, z. B. Japanisch, ist die Anzahl der Byte doppelt so hoch wie die Anzahl der Zeichen. HINWEIS: Das Wort “inline” bezieht sich auf den Teil der Felddaten, der in der Tabellenzeile gespeichert wird. Wenn der maximale Inline-Wert überschritten wird, werden die restlichen Daten als BLOB in einem separaten Strom gespeichert. Von Blackfish SQL unterstützte SQL-Datentypen Die folgende Tabelle beschreibt die von Blackfish SQL unterstützten SQL-Datentypen: Datentyp SQL-Entsprechung 1 8-Bit-Byte TINYINT BYTE 77 10 Blackfish SQL 16-Bit-Ganzzahl SMALLINT SHORT 32-Bit-Ganzzahl INT INTEGER 64-Bit-Ganzzahl BIGINT LONG Exakte Dezimalzahl DECIMAL(p,d) BIGDECIMAL(p,d) 64-Bit-Fließkommazahl FLOAT(p), p=24 bis 52 FLOAT DOUBLE DOUBLE PRECISION 32-Bit-Fließkommazahl REAL FLOAT(p), p=1 bis 23 Unicode-Zeichenfolge VARCHAR(p,m) STRING(p,m) Byte-Array VARBINARY(p,m) BINARY(p,m) INPUTSTREAM(p,m) Serialisierbares Objekt OBJECT(t,m) boolean BOOLEAN BIT Datum DATE Zeit TIME Zeitstempel TIMESTAMP 10 1 In der Spalte "SQL-Entsprechung" sind die besser portierbaren Formen fett dargestellt. Beispiele VARCHAR(30,10) Ein String mit einer maximalen Größe von 30 Zeichen. Die ersten 10 Byte werden inline gespeichert, die restlichen Byte in einem BLOB (ein separater Strom für große Objekte) VARCHAR(30) Ein String mit einer maximalen Größe von 30 Zeichen, die alle inline gespeichert werden, da die Genauigkeit geringer ist als der Standard-Inlinewert von 64 VARCHAR Ein String ohne Größenbeschränkung. Die ersten 64 Byte werden inline gespeichert, weitere Byte werden in einem BLOB gespeichert (ein separater Strom für große Objekte) DECIMAL(5,2) Ein Datenelement des Typs BigDecimal mit einer Genauigkeit von mindestens 5 und genau 2 Dezimalstellen DECIMAL(4) Ein Datenelement des Typs BigDecimal mit einer Genauigkeit von mindestens 4 und genau 0 Dezimalstellen DECIMAL Ein Datenelement des Typs BigDecimal mit Platz für mindestens 72 signifikante Stellen und genau 0 Dezimalstellen OBJECT Ein serialisierbares Java-Objekt OBJECT('java.math.BigInteger') Ein serialisierbares Java-Objekt, das aus java.math.BigInteger-Objekten bestehen muss 10 Literale Die folgende Tabelle enthält die Typen der unterstützten skalaren Literalwerte: Blackfish SQL-Datentyp SMALLINT BIGINT Beispiele INT 8 DECIMAL(p,d) Integer-Datentypen 2. 15.7 .9233 REAL DOUBLE 8E0 4E3 FLOAT(p) 6.2E-72 78 Beschreibung Ein genauer numerischer Wert, der einen Dezimalpunkt enthalten kann 0.3E2 Ein numerischer Annäherungswert: Eine Zahl mit nachgestelltem Buchstaben E, auf den eine Ganzzahl mit optionalem Vorzeichen folgt 10 Blackfish SQL VARCHAR(p,m) 'Hallo' 'tu''s nicht' VARBINARY(p,m) B'1011001' X'F08A' X'f777' Ein String: Muss in einfache Anführungszeichen gesetzt sein. Das einfache Anführungszeichen (als normales Schriftzeichen) wird durch zwei aufeinander folgende einzelne Anführungszeichen dargestellt Eine binäre oder hexadezimale Sequenz in einfachen Anführungszeichen und mit vorangestelltem Buchstaben B für binäre Sequenzen oder X für hexadezimale Sequenzen BOOLEAN TRUE FALSE DATE DATE '2002-06-17' Zeigt die lokale Ursprungszeit an. Das Format ist DATE 'yyyy-mm-dd' TIME TIME '15:46:55' Zeigt die lokale Ursprungszeit (24-Stunden-Format) TIMESTAMP TIMESTAMP '2001-12-31 13:15:45' Zeigt die lokale Anzeigezeit an. Das Format ist TIMESTAMP 'yyyy-mm-dd hh:mm:ss' an. Das Format ist TIME 'hh:mm:ss' HINWEIS: Es gibt zwei Objekt-Literale in Blackfish SQL. Schlüsselwörter Die nachfolgenden zwei Listen enthalten alle aktuellen Schlüsselwörter für Blackfish SQL. Die Wörter der ersten Liste sind reserviert und können nur dann als SQL-Bezeichner verwendet werden, wenn sie in Anführungszeichen eingeschlossen werden. Die Schlüsselwörter der zweiten Liste sind nicht reserviert und können sowohl mit als auch ohne Anführungszeichen verwendet werden. Beachten Sie, dass nicht alle SQL-92-Schlüsselwörter von der SQL-Engine des Blackfish SQL als Schlüsselwörter behandelt werden. Um maximale Portierbarkeit zu gewährleisten, sollten Sie keine Bezeichner verwenden, die in einem der SQL-Dialekte als Schlüsselwörter dienen. Reservierte Blackfish SQL-Schlüsselwörter Die Wörter in dieser Liste sind reservierte Schlüsselwörter. Sie können nur dann als SQL-Bezeichner verwendet werden, wenn sie von doppelten Anführungszeichen umgeben sind. Bei einer solchen Verwendung ist die Groß-/Kleinschreibung zu beachten. ABSOLUTE ACTION ADD ADMIN ADMINISTRATOR ALL ALTER AND ANY AS ASC AUTHORIZATION AUTOINCREMENT AVG BETWEEN BIT BIT_LENGTH BOTH BY CALL CASCADE CASE CAST CHAR CHAR_LENGTH CHARACTER CHARACTER_LENGTH CHECK COALESCE COLUMN CONSTRAINT COUNT CREATE CROSS CURRENT_DATE CURRENT_ROLE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER DATE DECIMAL DEFAULT DELETE DESC DISTINCT DOUBLE DROP ELSE END ESCAPE EXCEPT EXECUTE EXISTS EXTRACT FALSE FLOAT FOR FOREIGN FROM FULL GRANT GROUP HAVING IN INDEX INNER INSERT INT INTEGER INTERSECT INTO IS ISOLATION JOIN KEY LEADING LEFT LEVEL LIKE LOWER MAX MIN NATURAL NO NONE NOT NULL NULLIF NUMERIC OCTET_LENGTH ON ONLY OPTION OR ORDER OUTER POSITION PRECISION PRIMARY PRIVILEGES PUBLIC REAL REFERENCES RENAME RESOLVABLE RESTRICT REVOKE RIGHT SCHEMA SELECT SET SMALLINT SOME SQRT STARTUP SUBSTRING SUM TABLE THEN TIME TIMESTAMP TO TRAILING TRANSACTION TRIM TRUE UNION UNIQUE UNKNOWN UPDATE UPPER USER USING VALUES VARCHAR VARYING VIEW WHEN WHERE WITH Nicht reservierte Blackfish SQL-Schlüsselwörter Die Schlüsselwörter in der folgenden Liste sind nicht reserviert. Sie können sowohl mit als auch ohne Anführungszeichen als SQL-Bezeichner verwendet werden. Wenn sie ohne Anführungszeichen verwendet werden, wird die Groß-/Kleinschreibung nicht beachtet und alle Buchstaben werden vom SQL-Parser als Großbuchstaben interpretiert. Wenn sie in Anführungszeichen eingeschlossen werden, wird die Groß-/Kleinschreibung beachtet. 79 10 Blackfish SQL ABS AUTOCOMMIT BOOLEAN BIGDECIMAL BIGINT BINARY BYTE CASEINSENSITIVE CLASS COMMIT COMMITTED CONCAT CONVERT CURDATE CURTIME D DAY DAYOFMONTH DEC FN GRANTED HOUR IFNULL INPUTSTREAM METHOD LCASE LENGTH LOCATE LOCK LONG LONGINT LONGVARBINARY LONGVARCHAR LTRIM METHOD MINUTE MONTH NOW NOWAIT OBJECT OFF OJ PASSWORD READ REPEATABLE ROLE ROLLBACK RTRIM SECOND SERIALIZABLE 10 SHORT STRING T TIMESTAMPADD TIMESTAMPDIFF TIMEZONEHOUR TIMEZONEMINUTE TINYINT TS TYPE UCASE UNCOMMITTED VARBINARY WORK WRITE YEAR Bezeichner Bei SQL-Bezeichnern, die nicht in Anführungszeichen eingeschlossen sind, wird nicht zwischen Groß- und Kleinschreibung unterschieden. Sie werden behandelt, als wären sie komplett in Großbuchstaben geschrieben. Ist ein Bezeichner in doppelte Anführungszeichen eingeschlossen, wird zwischen Groß- und Kleinschreibung unterschieden. Für Bezeichner ohne Anführungszeichen gelten die folgenden Regeln: • Das erste Zeichen muss ein Buchstabe sein, der von der Klasse java.lang.Character erkannt wird. • Als restliche Zeichen kommen nur Buchstaben, Ziffern, Unterstriche (_) und Dollar-Zeichen ($) in Frage. • Schlüsselwörter können nicht als Bezeichner verwendet werden. Bezeichner in Anführungszeichen können jeden beliebigen Zeichen-String enthalten. Leerzeichen, Symbole und Schlüsselwörter sind erlaubt. Beispiele Gültige Bezeichner Bezeichner Beschreibung customer Wird als CUSTOMER behandelt Help_me Wird als HELP_ME behandelt "Hansen" Wird als Hansen behandelt "" Wird als einfaches Leerzeichen behandelt Ungültige Bezeichner: Bezeichner Problem _order Muss mit einem Buchstaben beginnen DATE date ist ein reserviertes Schlüsselwort borland.com Punkte sind nicht zulässig In der folgenden Liste finden Sie unterschiedliche Schreibweisen für denselben Bezeichner. In diesem Beispiel LAST_NAME: 10 • last_name • Last_Name • lAsT_nAmE • "LAST_NAME" Listensyntax Der folgende Abschnitt enthält Elementnamen, die mit “list” oder “commalist” enden, die nicht weiter definiert sind. Beispiel: <select item commalist> <column constraint list> Diese Definitionen sind als kommagetrennte Listen mit mindestens einem Element zu lesen (im Fall von "commalist"): <select item commalist> ::= 80 10 Blackfish SQL <select item> [ , <select item> ] * <column constraint list> ::= <column constraint> [ <column constraint> ] * Ausdrücke Ausdrücke werden in der SQL-Sprache häufig verwendet. Sie enthalten mehrere Infix-Operatoren und einige wenige Präfix-Operatoren. Nachfolgend die Liste der Operatoren in absteigender Priorität: • Präfix + • Infix * / • Infix + - || • Infix = <> < > <= >= • Präfix NOT • Infix AND • Infix OR Syntax <expression> ::= <scalar expression> | <conditional expression> <scalar expression> ::= <scalar expression> {+ | - | * | / | <concat> } <scalar expression> | {+ | -} <scalar expression> | ( <expression> ) | ( <table expression> ) | <column reference> | <user defined function reference> | <literal> | <aggregator function> | <function> | <parameter marker> Eine Liste der unterstützten Funktionen in Blackfish SQL finden Sie unter "Funktionen". <conditional expression> ::= <conditional expression> OR <conditional expression> | <conditional expression> AND <conditional expression> | NOT <conditional expression> | <scalar expression> <compare operator> <scalar expression> | <scalar expression> <compare operator> { ANY | SOME | ALL } (<table expression>) | <scalar expression> [NOT] BETWEEN <scalar expression> | <scalar expression> [NOT] LIKE <scalar expression> [ ESCAPE <scalar expression> ] | <scalar expression> [NOT] IS { NULL | TRUE | FALSE | UNKNOWN } | <scalar expression> IN ( <scalar expression commalist> ) | <scalar expression> IN ( <table expression> ) | EXISTS ( <table expression> ) <compare operator> ::= = | <> | < | > | <= | >= <concat> ::= || <table expression> ::= <table expression> UNION [ ALL ] <table expression> | <table expression> EXCEPT [ ALL ] <table expression> | <table expression> INTERSECT [ ALL ] <table expression> | <join expression> | <select expression> | ( <table expression> ) <aggregator function> ::= 10 81 Blackfish SQL 10 <aggregator name> ( <expression> ) | COUNT ( * ) <aggregator name> ::= AVG | SUM | MIN | MAX | COUNT <column reference> ::= [ <table qualifier> . ] <column name> <user defined function reference> ::= <method name> ([ <expression commalist> ]) <table qualifier> ::= <table name> | <correlation name> <correlation name> ::= <SQL identifier> Beispiele Die folgende Anweisung wählt den berechneten Wert von Amount mal Price aus der Tabelle Orders für Bestellungen eines anzugebenden Kunden im Januar: SELECT Amount * Price FROM Orders WHERE CustId = ? AND EXTRACT(MONTH FROM Ordered) = 1; Die folgende Anweisung ruft Daten mithilfe einer skalaren Unterabfrage ab: SELECT Name, (SELECT JobName FROM Job WHERE Id=Person.JobId) FROM Person; Wenn die Unterabfrage mehr als eine Zeile zurückgibt, ist ein Fehler aufgetreten. Prädikate In Bedingungsausdrücken werden die folgenden Prädikate unterstützt. BETWEEN Das Prädikat BETWEEN definiert einen einschließenden Wertebereich. Das Resultat aus expr BETWEEN leftExpr AND rightExpr ist gleichbedeutend mit dem Ausdruck: leftExpr <= expr AND expr <= rightExpr Syntax <between expression> ::= <scalar expression> [NOT] BETWEEN <scalar expression> AND <scalar expression> 10 Beispiel Die folgende Anweisung wählt alle Bestellungen aus, bei denen ein Kunde eine bestimmte Stückzahl (zwischen 3 und 7) eines Produkts bestellt: SELECT * from Orders WHERE Amount BETWEEN 3 AND 7; EXISTS Ein EXISTS-Ausdruck, der entweder TRUE oder FALSE ergibt, abhängig davon, ob Elemente in einer Ergebnistabelle enthalten sind. Syntax 82 10 Blackfish SQL <exists predicate> ::= EXISTS ( <table expression> ) Beispiel Die folgende Anweisung sucht alle Tauchartikel, bei denen der Beginn des Namens mit dem Beginn des Namens eines anderen Artikels übereinstimmt. SELECT * FROM zodiac z WHERE EXISTS ( SELECT * FROM zodiac z2 WHERE POSITION(z.name IN z2.name) = 1 AND z.name < > z2.name ); IN Die IN-Klausel enthält eine Liste mit Werten, mit denen es eine Übereinstimmung geben muss. Alle Werte in der Liste werden in der SELECT-Anweisung, die die IN-Klausel enthält, als Werte betrachtet, mit denen eine Übereinstimmung vorhanden sein muss. Syntax <in expression> ::= <scalar expression> IN ( <scalar expression commalist> ) Beispiel Die folgende Anweisung gibt alle Datensätze zurück, bei denen der Name entweder "leo" oder "aquarius" lautet: SELECT * FROM sternzeichen WHERE name IN ('löwe', 'wassermann'); Die IN-Klausel hat auch einen Variant-Wert, wenn eine Unterabfrage statt einer Ausdrucksliste verwendet wird. Syntax <in expression> ::= <scalar expression> IN ( <table expression> ) Beispiel SELECT * FROM zodiac WHERE name IN (SELECT name FROM people); IS Das Prädikat IS ermöglicht das Testen von Ausdrücken. Jeder Ausdruck kann die Auswertung NULL ergeben, Bedingungsausdrücke können jedoch nur eine der Auswertungen TRUE, FALSE oder UNKNOWN ergeben. UNKNOWN ist in Bedingungsausdrücken gleichbedeutend mit NULL. Beachten Sie, dass bei SELECT-Abfragen mit einer WHERE-Klausel nur die Zeilen einbezogen werden, die den Wert TRUE zurückgeben. Wenn der Ausdruck FALSE oder UNKNOWN zurückgibt, wird die Zeile nicht einbezogen. Das Prädikat IS kann zwei Ergebnisse ausgeben: TRUE oder FALSE. Syntax <is expression> ::= <scalar expression> IS [NOT] { NULL | TRUE | FALSE | UNKNOWN } Beispiele TRUE IS TRUE ergibt TRUE. FALSE IS NULL ergibt FALSE. LIKE Das Prädikat LIKE ermöglicht in SQL einen einfachen String-Mustervergleich. Das Suchargument, das Muster und das Escape-Zeichen (falls verwendet) müssen ausnahmslos Strings ausgeben. Das Muster kann auch die speziellen 83 10 Blackfish SQL 10 Platzhalterzeichen _ und % enthalten. Dabei gilt: • Ein Unterstrich (_) kann für jedes einzelne Zeichen stehen. • Ein Prozentzeichen (%) kann für jede Sequenz aus n Zeichen stehen, unter der Bedingung n >= 0 Wenn das Escape-Zeichen verwendet wird, können diese beiden speziellen Platzhalterzeichen im Suchmuster verwendet werden. Beim Mustervergleich wird zwischen Groß- und Kleinschreibung unterschieden. Soll die Groß-/Kleinschreibung nicht beachtet werden, müssen Sie den Suchbegriff mithilfe der Funktion LOWER bzw. UPPER modifizieren. Syntax <like expression> ::= <search item> [NOT] LIKE <pattern> [ ESCAPE <escape char> ] <search item> <pattern> ::= <scalar expression> ::= <scalar expression> <escape char> ::= <scalar expression> Beispiele 1. Der folgende Ausdruck ergibt TRUE, wenn Item an einer beliebigen Stelle den Teilstring "shoe" enthält. Item LIKE '%shoe%' 2. Die Auswertung ergibt TRUE, wenn Item exakt drei Zeichen lang ist und mit dem Buchstaben "S" beginnt. Item LIKE 'S__' 3. Der folgende Ausdruck ergibt TRUE, wenn Item mit einem Prozentzeichen endet. Das Zeichen * wird in diesem Beispiel über die Zusatzklausel ESCAPE als Escape-Zeichen für die beiden Sonderzeichen definiert. Wenn "*" einem dieser Sonderzeichen vorangestellt wird, wird das Sonderzeichen innerhalb des Musters als normales Zeichen behandelt. Item Like '%*%' ESCAPE '*' Quantifizierte Vergleiche Ein Ausdruck kann mit einigen oder allen Elementen einer Ergebnistabelle verglichen werden. Syntax <quantified comparison> ::= <scalar expression> <compare operator> { ANY | SOME | ALL } ( <table expression> ) Beispiel SELECT * FROM sternzeichen WHERE quantify <= ALL ( SELECT quantify FROM sternzeichen ); 10 Funktionen String-Funktionen können auf Strings beliebiger Länge angewandt werden. Da große Strings als BLOBs gespeichert werden, sollten Sie große Textfelder als VARCHAR definieren, um Suchen zu ermöglichen. ABSOLUTE Die ABSOLUTE-Funktion kann nur für numerische Ausdrücke verwendet werden und gibt den absoluten Wert der übergebenen Zahl zurück. Syntax <absolute function> ::= ABSOLUTE( <expression> ) Beispiel SELECT * FROM Scapes WHERE ABSOLUTE( Height - Width ) < 50; 84 10 Blackfish SQL BIT_LENGTH Die BIT_LENGTH-Funktion liefert die Länge eines STRING-, INPUTSTREAM- oder OBJECT-Werts in Bit. Syntax <bit length function> ::= BIT_LENGTH( <expression> ) Beispiel SELECT * FROM TABLE1 WHERE BIT_LENGTH( binary_column ) > 8192; case Die CASE-Funktion gibt einen Bedingungswert zurück. Syntax <case function> ::= CASE [ <expression> ] <when clause commalist> ELSE <expression> END <when clause> ::= WHEN <expression> THEN <expression> Beispiele CASE WHEN COL1 > 50 THEN 'Heavy Item' WHEN COL1 > 25 THEN 'Middle weight Item' WHEN COL1 > 0 THEN 'Light Item' ELSE 'No weight specified' END CASE COL2 WHEN 4 THEN 'A' WHEN 3 THEN 'B' WHEN 2 THEN 'C' WHEN 1 THEN 'D' ELSE 'Invalid Grade' END 10 CAST Die CAST-Funktion wandelt einen Datentyp in einen anderen Datentyp um. Syntax <cast function> ::= CAST ( <column name> AS <data type> ) Beispiel Im folgenden Beispiel wird eine Zeile ausgegeben, in der die ID einer String-Spalte dem Wert '001234' entspricht SELECT * FROM employee WHERE CAST ( id AS long ) = 1234; 85 Blackfish SQL 10 CHAR_LENGTH und CHARACTER_LENGTH Die SQL-Funktionen CHAR_LENGTH und CHARACTER_LENGTH geben die Länge eines bestimmten Strings aus. Syntax <char length function> ::= CHAR_LENGTH ( <scalar expression> ) CHARACTER_LENGTH ( <scalar expression> ) COALESCE Die COALESCE-Funktion gibt den ersten nicht NULL lautenden Wert aus der Ausdrucksliste zurück. Syntax <coalesce function> ::= COALESCE( expression commalist ) Beispiel Mit folgender Anweisung wird eine Namensliste erzeugt. Der Name ist last_name, wenn diese Spalte nicht NULL ist, ansonsten ist der Name first_name. SELECT COALESCE(last_name, first_name) AS name FROM table1; CURRENT_DATE, CURRENT_TIME und CURRENT_TIMESTAMP Diese SQL-Funktionen geben das aktuelle Datum und/oder die Uhrzeit aus. Wenn eine dieser Funktionen innerhalb einer Anweisung mehrmals verwendet wird, gibt sie jedes Mal, wenn die Anweisung ausgeführt wird, dasselbe Ergebnis aus. Beispiel SELECT * from Returns where ReturnDate <= CURRENT_DATE; CURRENT_ROLE Die CURRENT_ROLE-Funktion gibt die aktuelle Rolle zurück oder NULL, wenn mithilfe der Anweisung SET ROLE keine Rolle festgelegt wurde. Syntax <current_role_function> ::= CURRENT_ROLE 10 Beispiel Die folgende Anweisung gibt alle Daten aus der CUSTOMERS-Tabelle zurück, die mit der MANAGER-Rolle in diese Tabelle eingetragen wurden. Die Spalte SOURCE hat den Datentyp VARCHAR. SET ROLE MANAGER; SELECT * FROM CUSTOMERS WHERE SOURCE = CURRENT_ROLE; CURRENT_USER Die Funktion CURRENT_USER gibt den Namen des aktuellen Benutzers zurück. Syntax 86 10 Blackfish SQL <current_user function> ::= CURRENT_USER Beispiel Die folgende Anweisung gibt alle Daten aus der INVOICES-Tabelle zurück, die vom aktuellen Benutzer in diese Tabelle eingetragen wurden. Die Spalte SOURCE hat den Datentyp VARCHAR. SELECT * FROM INVOICES WHERE SOURCE = CURRENT_USER; EXTRACT Die SQL-Funktion EXTRACT extrahiert Teile von Datums- und Zeitwerten. Bei dem Ausdruck kann es sich um einen Wert vom Typ DATE, TIME oder TIMESTAMP handeln. Syntax <extract function> ::= EXTRACT ( <extract field> FROM <scalar expression> ) <extract field> ::= YEAR | MONTH | DAY | HOUR | MINUTE | SECOND Beispiele EXTRACT(MONTH FROM DATE '1999-05-17') ergibt 5. EXTRACT(HOUR FROM TIME '18:00:00') ergibt 18. EXTRACT(HOUR FROM DATE '1999-05-17') ergibt eine Ausnahme. LOWER und UPPER Die SQL-Funktionen LOWER und UPPER konvertieren den angegebenen String vollständig in Groß- bzw. in Kleinschreibung. Syntax <lower function> ::= LOWER ( <scalar expression> ) <upper function> ::= UPPER ( <scalar expression> ) 10 NULLIF Die NULLIF-Funktion vergleicht zwei Ausdrücke. Sie gibt NULL zurück, wenn die Ausdrücke gleichwertig sind. Anderenfalls wird der erste Ausdruck zurückgegeben. Die Funktion ist logisch vergleichbar mit folgendem CASE-Ausdruck: CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END. Syntax <NULLIF> ::= ( <scalar expression>, <scalar expression> ) Beispiel Folgende Anweisung gibt für jede Zeile in TABLE1 eine Zeile mit last_name zurück, wenn sich der Vorname vom Nachnamen unterscheidet. Ist first_name identisch mit last_name, wird NULL zurückgegeben. 87 Blackfish SQL 10 SELECT NULLIF(last_name,first_name) FROM TABLE1; OCTET_LENGTH Die Funktion OCTET_LENGTH gibt die Länge eines STRING-, INPUTSTREAM- oder OBJECT-Werts in Byte zurück. Syntax <octet_length> ::= OCTET_LENGTH(<expression>) Beispiel SELECT * FROM TABLE1 WHERE OCTET_LENGTH(binary_column)>1024; POSITION Die SQL-Funktion POSITION gibt die Position eines Strings innerhalb eines anderen Strings aus. Gibt eines der Argumente NULL zurück, ist das Ergebnis NULL. Syntax <position function> ::= POSITION ( <string> IN <another> ) Beispiele POSITION('BCD' IN 'ABCDEFG') ergibt 2. POSITION('' IN 'ABCDEFG') ergibt 1. POSITION('TAG' IN 'ABCDEFG') ergibt 0. SQRT Die Funktion SQRT kann nur für numerische Ausdrücke verwendet werden und berechnet die Quadratwurzel der übergebenen Zahl. Syntax <sqrt function> ::= SQRT( <expression> ) Beispiel SELECT * FROM Scapes WHERE SQRT(HEIGHT*WIDTH - ?) > ?; 10 SUBSTRING Die SQL-Funktion SUBSTRING extrahiert aus einem bestimmten String einen Substring. Hat einer der Operanden den Wert NULL, ist das Ergebnis NULL. Die start-Position gibt die erste Zeichenposition des Substrings an, wobei 1 das erste Zeichen angibt. Wird FOR verwendet, gibt dieses die Länge des resultierenden Strings an. Syntax <substring function> ::= SUBSTRING ( <string expression> FROM <start pos> [ FOR <length> ] ) Beispiele SUBSTRING('ABCDEFG' FROM 2 FOR 3) ergibt 'BCD'. 88 10 Blackfish SQL SUBSTRING('ABCDEFG' FROM 4) ergibt 'DEFG'. SUBSTRING('ABCDEFG' FROM 10) ergibt ''. SUBSTRING('ABCDEFG' FROM -6 FOR 3) ergibt 'ABC'. SUBSTRING('ABCEDFG' FROM 2 FOR -1) führt zu einer Ausnahme. TRIM Die SQL-Funktion TRIM entfernt vorangestellte und/oder nachgestellte Füllzeichen aus einem String. Das Element <padding> muss ein String der Länge 1 sein; dies ist das Zeichen, das aus dem String entfernt werden soll. • Wird <padding> weggelassen, werden Leerzeichen entfernt. • Wird <trim spec> weggelassen, gilt das Schlüsselwort BOTH. • Werden sowohl <padding> als auch <trim spec> weggelassen, muss auch das Schlüsselwort FROM weggelassen werden. Syntax <trim function> ::= TRIM ( [<trim spec>] [<padding>] [FROM] <scalar expression> ) <trim spec> ::= LEADING | TRAILING | BOTH <padding> ::= <scalar expression> Beispiele TRIM(' Hallo Welt ') ergibt 'Hallo Welt'. TRIM(LEADING '0' FROM '00000789.75') ergibt '789.75'. USER 10 Die USER-Funktion gibt den Namen des aktuellen Benutzers zurück. Diese Funktion entspricht der Funktion CURRENT_USER. Syntax <user function> ::= USER Beispiel Die folgende Anweisung gibt alle Daten aus der INVOICES-Tabelle zurück, die vom aktuellen Benutzer in diese Tabelle eingetragen wurden. SELECT * FROM INVOICES WHERE SOURCE = USER; Tabellenausdrücke In diesem Abschnitt werden einige Konventionen beschrieben, die in der folgenden Anweisungsreferenz verwendet werden. Dabei handelt es sich um: 89 Blackfish SQL 10 • Select-Ausdrücke • Union-Operatoren, Intersection-Operatoren und Except-Operatoren • Join-Ausdrücke <table expression> ::= <table expression> UNION [ALL] <table expression> | <table expression> EXCEPT [ALL] <table expression> | <table expression> INTERSECT [ALL] <table expression> | <join expression> | <select expression> | ( <table expression> ) Select-Ausdrücke Ein Select-Ausdruck ist der Tabellenausdruck, der in einer SELECT-Anweisung am häufigsten verwendet wird. • Geben Sie DISTINCT an, um alle Duplikate aus dem Ergebnissatz zu entfernen. • Geben Sie GROUP BY und HAVING in Verbindung mit Aggregatfunktionen an, um Zusammenfassungswerte aus den Daten einer Tabelle zu berechnen. Mit der WHERE-Klausel (falls vorhanden) wird die Anzahl der Zeilen in der Zusammenfassung begrenzt. Wenn eine Aggregatfunktion ohne eine GROUP BY-Klausel verwendet wird, wird eine Zusammenfassung für die gesamte Tabelle berechnet. Wenn eine GROUP BY-Klausel vorhanden ist, wird eine Zusammenfassung für jeden eindeutigen Wertesatz aus den in GROUP BY aufgeführten Spalten berechnet. Wenn die HAVING-Klausel vorhanden ist, werden anhand des Bedingungsausdrucks in der HAVING-Klausel komplette Gruppen herausgefiltert. Bei Zusammenfassungsabfragen gelten zusätzliche Regeln für die Positionen, an denen Spalten in Ausdrücken vorkommen können: • Die WHERE-Klausel kann keine Aggregatfunktionen enthalten. • Spaltenreferenzen, die außerhalb eines Aggregators vorkommen, müssen in der GROUP BY-Klausel enthalten sein. • Aggregatfunktionen können nicht verschachtelt werden. Syntax <select expression> ::= SELECT [ ALL | DISTINCT ] <select item commalist> FROM <table reference commalist> [ WHERE <conditional expression> ] [ GROUP BY <column reference commalist> ] [ HAVING <conditional expression> ] <select item> ::= <scalar expression> [ [AS] <output column name> ] | [ <range variable> . ] * <table reference> ::= <join expression> | <table name> [ <output table rename> ] | ( <table expression> ) [ <output table rename> ] 10 <output table rename> ::= [AS] <range variable> [ ( <column name commalist> ) ] <conditional expression> ::= <conditional expression> OR <conditional expression> <conditional expression> AND <conditional expression> NOT <conditional expression> <scalar expression> <compare operator> <scalar expression> <scalar expression> <compare operator> { ANY | SOME | ALL } (<table expression>) | <scalar expression> [NOT] BETWEEN <scalar expression> | <scalar expression> [NOT] LIKE <scalar expression> [ ESCAPE <scalar expression> ] | | | | 90 10 Blackfish SQL | | | | <scalar expression> [NOT] IS { NULL | TRUE | FALSE | UNKNOWN } <scalar expression> IN ( <scalar expression commalist> ) <scalar expression> IN ( <table expression> ) EXISTS ( <table expression> ) <column reference> ::= [ <table qualifier> . ] <column name> <scalar expression> ::= <scalar expression> {+ | - | * | / | <concat> } <scalar expression> | {+ | -} <scalar expression> | ( <expression> ) | ( <table expression> ) | <column reference> | <user defined function reference> | <literal> | <aggregator function> | <function> | <parameter marker> <table name> ::= [ <schema name> . ] <SQL identifier> <schema name> ::= <SQL identifier> <user defined function reference> ::= <method name> ([ <expression commalist> ]) Beispiel 1 Folgende Anweisung gibt eine einzelne Zeile mit dem Gesamtwert aller Bestellungen (Orders) aus. SELECT SUM(Amount * Price) FROM Orders; Beispiel 2 Folgende Anweisung gibt ein einzelne Zeile mit der Anzahl der Bestellungen zurück, wobei Amount beim Kunde 123 nicht NULL ist. SELECT COUNT(Amount) FROM Orders WHERE CustId = 123; Beispiel 3 Folgende Anweisung gibt mehrere Zeilen zurück, mit dem Gesamtwert aller Bestellungen nach Kunden gruppiert, für alle Kunden mit einer ID unter 200. SELECT CustId, SUM(Amount * Price), COUNT(Amount) WHERE CustId < 200 GROUP BY CustId; 10 Beispiel 4 Folgendes Beispiel gibt Kunden mit dem Gesamtvolumen aller Bestellungen zurück, wenn das Gesamtvolumen einen bestimmten Betrag überschreitet. SELECT CustId, SUM(Amount * Price), COUNT(Amount) GROUP BY CustId HAVING SUM(Amount * Price) > 500000; Beispiel 5 Folgende Anweisung ist nicht zulässig, weil sie verschachtelte Aggregatfunktionen enthält. SELECT CustId, COUNT(23 + SUM(Amount)) GROUP BY CustId; Beispiel 6 Folgende Anweisung ist nicht zulässig, weil die Spalte CustId in der Select-Liste referenziert wird, aber in der GROUP BY-Referenzliste nicht vorhanden ist. 91 Blackfish SQL 10 SELECT CustId, SUM(Amount* Price) GROUP BY Amount; Die Syntax für Tabellenausdrücke finden Sie unter "Tabellenausdrücke". Union-Operatoren, Intersection-Operatoren und Except-Operatoren Ein Tabellenausdruck ist ein Ausdruck, dessen Auswertung eine unbenannte Tabelle ergibt. Von den folgenden Operatoren bindet INTERSECT am meisten; UNION und EXCEPT sind gleichwertig. UNION ALL Erstellt eine Union aus zwei Tabellen inklusive aller Duplikate. UNION Erstellt eine Union aus zwei Tabellen. Wenn eine Zeile in beiden Tabellen mehrmals vorkommt, ist diese Zeile im Ergebnis genau zweimal enthalten. Andere Zeilen im Ergebnissatz haben keine Duplikate. INTERSECTION Erstellt die Schnittmenge aus zwei Tabellen inklusive aller Duplikate. ALL INTERSECTION Erstellt die Schnittmenge zweier Tabellen. Wenn eine Zeile in beiden Tabellen doppelt vorkommt, enthält der Ergebnissatz diese Zeile genau zweimal. Andere Zeilen im Ergebnissatz haben keine Duplikate. EXCEPT ALL Erstellt eine Tabelle, die alle Zeilen enthält, die nur in der ersten Tabelle vorkommen. Wenn eine Zeile m-mal in der ersten Tabelle und n-mal in der zweiten enthalten ist, enthält der Ergebnissatz diese Zeile m-n-mal. EXCEPT Erstellt eine Tabelle, die alle Zeilen enthält, die nur in der ersten Tabelle vorkommen. Wenn eine Zeile m-mal in der ersten Tabelle und n-mal in der zweiten enthalten ist, enthält der Ergebnissatz diese Zeile genau zweimal, wenn m >= 1 und n = 0. Andere Zeilen im Ergebnissatz haben keine Duplikate. Beispiel 1 SELECT * FROM T1 UNION SELECT * FROM T2 UNION SELECT * FROM T3; wird ausgeführt als: (SELECT * FROM T1 UNION SELECT * FROM T2) UNION SELECT * FROM T3; Beispiel 2 SELECT * FROM T1 UNION SELECT * FROM T2 INTERSECT SELECT * FROM T3; wird ausgeführt als: SELECT * FROM T1 UNION (SELECT * FROM T2 INTERSECT SELECT * FROM T3); Join-Ausdrücke In Blackfish SQL ermöglichen Join-Ausdrücke den Zugriff auf eine Vielzahl von join-Mechanismen. Die am häufigsten verwendeten Joins, innere (inner joins) und zirkuläre Joins (cross joins), können nur in Verbindung mit dem SELECT-Ausdruck verwendet werden, äußere Joins (outer joins) müssen den JOIN-Ausdruck enthalten. 10 92 CROSS JOIN A CROSS JOIN B führt zur gleichen Ergebnismenge wie SELECT A.*, B.* FROM A,B INNER JOIN A INNER JOIN B ON A.X=B.X führt zu derselben Ergebnismenge wie SELECT A.*, B.* FROM A,B WHERE A.X=B.X LEFT OUTER A LEFT OUTER JOIN B ON A.X=B.X gibt die Zeilen aus dem entsprechenden INNER JOIN plus der Zeilen aus A zurück, auch wenn keine entsprechenden Werte für Datensätze in B existieren, wobei die leeren Stellen mit NULL-Werten aufgefüllt werden. RIGHT OUTER A RIGHT OUTER JOIN B ON A.X=B.X gibt die Zeilen aus dem entsprechenden INNER JOIN plus der Zeilen aus B zurück, auch wenn dort keine entsprechenden Werte existieren, wobei die leeren Stellen mit NULL-Werten aufgefüllt werden. 10 Blackfish SQL FULL OUTER A FULL OUTER JOIN B ON A.X=B.X gibt die Zeilen aus dem entsprechenden INNER JOIN plus der Zeilen aus A und B zurück, auch wenn dort keine entsprechenden Werte für Zeilen in A und B existieren, wobei die leeren Stellen mit NULL-Werten aufgefüllt werden. UNION A UNION JOIN B führt zu einer ähnlichen Ergebnismenge wie der folgenden: A LEFT OUTER JOIN B ON FALSE UNION ALL A RIGHT OUTER JOIN B ON FALSE eine Tabelle mit Spalten für alle Spalten in A und B. Die Zeilen aus A enthalten NULL-Werte für die aus B angehängten Spalten. Die Zeilen aus B enthalten NULL-Werte für die aus A angehängten Spalten. Die folgenden Ausdrücke schließen sich gegenseitig aus: ON ON ist ein Ausdruck, der bei einem JOIN-Ausdruck erfüllt sein muss. USING USING( C1, C2, C3) ist äquivalent zum ON-Ausdruck bei A.C1=B.C1 AND A.C2=B.C2 AND A.C3=B.C3, mit der Ausnahme, dass in der Ergebnistabelle die Spalten C1, C2 und C3 nur einmal enthalten sind und die ersten drei Spalten der Tabelle bilden. NATURAL NATURAL ist dasselbe wie eine USING-Klausel und gibt die Spaltennamen aus, die in Tabelle A und in Tabelle B vorkommen. Syntax <join expression> ::= <table reference> CROSS JOIN <table reference> | <table reference> [NATURAL] [INNER] JOIN <table reference> [ <join kind> ] | <table reference> [NATURAL] LEFT [OUTER] JOIN <table reference> [ <join kind> ] | <table reference> [NATURAL] RIGHT [OUTER] JOIN <table reference> [ <join kind> ] | <table reference> [NATURAL] FULL [OUTER] JOIN <table reference> [ <join kind> ] | <table reference> UNION JOIN <table reference> <table reference> ::= <join expression> | <table name> [ <output table rename> ] <table reference> CROSS JOIN <table reference> | <table reference> [NATURAL] [INNER] JOIN <table reference> [ <join kind> ] | <table reference> [NATURAL] LEFT [OUTER] JOIN <table reference> [ <join kind> ] | <table reference> [NATURAL] RIGHT [OUTER] JOIN <table reference> [ <join kind> ] | <table reference> [NATURAL] FULL [OUTER] JOIN <table reference> [ <join kind> ] | <table reference> UNION JOIN <table reference> 10 <table reference> ::= <join expression> | <table name> [ <output table rename> ]| ( <table expression> ) [ <output table rename> ] <output table rename> ::= [AS] <range variable> [ ( <column name commalist> ) ] <range variable> ::= <SQL identifier> <join kind> ::= ON <conditional expression> 93 Blackfish SQL 10 | USING ( <column name commalist> ) Beispiele SELECT * FROM Tinvoice FULL OUTER JOIN Titem USING ("InvoiceNumber"); SELECT * FROM Tinvoice LEFT JOIN Titem ON Tinvoice."InvoiceNumber" = Titem."InvoiceNumber"; SELECT * FROM Tinvoice NATURAL RIGHT OUTER JOIN Titem; SELECT * FROM Tinvoice INNER JOIN Titem USING ("InvoiceNumber"); SELECT * FROM Tinvoice JOIN Titem ON Tinvoice."InvoiceNumber" = Titem."InvoiceNumber"; Anweisungen Der Blackfish SQL-JDBC-Treiber unterstützt eine Teilmenge des Standards ANSI/ISO SQL-92. Grundsätzlich werden die folgenden Komponenten unterstützt: • DDL (Data Definition Language) für die Verwaltung von Tabellen und Indizes, Schemas, Ansichten und Sicherheitselementen. • Datenbearbeitung und -auswahl mit INSERT, UPDATE, DELETE und SELECT, jedoch keine Cursor. • Unterstützung für allgemeine Tabellenausdrücke, z. B. JOIN, UNION und INTERSECT. Bei Blackfish SQL für Java werden Cursor-Operationen durch die JDBC Version 3.0 ResultSet-API unterstützt. Syntax <SQL statement> ::= <data definition statement> | <transaction control statement> | <data manipulation statement> <data definition statement> ::= <create schema statement> | <drop schema statement> | <create table statement> | <alter table statement> | <drop table statement> | <create view statement> | <alter view statement> | <drop view statement> | <create index statement> | <drop index statement> | <create method statement> | <drop method statement> | <create class statement> | <drop class statement> | <create user statement> | <alter user statement> | <drop user statement> | <create role statement> | <drop role statement> | <grant statement> | <revoke statement> | <set role statement> <transaction control statement> ::= <commit statement> | <rollback statement> | <set autocommit statement> | <set transaction statement> 10 <data manipulation statement> ::= <select statement> | <single row select statement> | <delete statement> 94 10 Blackfish SQL | | | | <insert statement> <update statement> <call statement> <lock statement> Anweisungen zur Datendefinition CREATE SCHEMA Mit der Anweisung CREATE SCHEMA wird ein Namespace für Tabellen, Ansichten und Methoden erstellt. Mit ihr können Sie mehrere Objekte in einer SQL-Anweisung erstellen. • Sie können eine Tabelle, Ansicht oder Methode auf zwei Arten in einem vorhandenen Schema erstellen: • Sie können diese als Teil einer CREATE SCHEMA-Anweisung erstellen. • Sie können einen Schemanamen als Teil des Objektnamens angeben, wenn Sie CREATE TABLE, CREATE VIEW oder CREATE METHOD als einzelne Anweisung verwenden. Im letzteren Fall (z. B. bei Verwendung von CREATE TABLE) müssen Sie einen Schemanamen angeben, der bereits vorhanden ist. • Um in einem neuen Schema ein Objekt zu erstellen, geben sie in der CREATE SCHEMA-Anweisung einen neuen Schemanamen an und erstellen Sie dann die Tabelle, Ansicht oder Methode als Teil der CREATE SCHEMA-Anweisung. • In der AUTHORIZATION-Klausel wird der Name des Eigentümers des Schemas angegeben. Wenn Sie keinen Eigentümer angeben, wird der Benutzer der SQL-Sitzung als Eigentümer betrachtet. Nur ein Administrator kann einen anderen als den eigenen Benutzernamen in der AUTHORIZATION-Klausel angeben. • Wenn Sie eine einzelne CREATE TABLE-, CREATE VIEW oder CREATE METHOD-Anweisung verwenden (d. h. die Anweisung ist nicht in eine CREATE SCHEMA-Anweisung eingebettet) und Sie keinen Schemanamen als Teil der CREATE-Anweisung angeben, verwendet JDataStore folgenden Algorithmus zur Zuweisung des neuen Objekts zu einem Schema: • Wenn Sie explizit ein Schema erstellt haben und dieses denselben Namen hat wie Ihr aktueller Benutzername, ist dieses Schema Ihr persönliches Standardschema. Die Tabelle, Ansicht oder Methode gehört zu Ihrem Standardschema. • Wenn Sie kein persönliches Standardschema erstellt haben, gehört die Tabelle, Ansicht oder Methode zum Schema DEFAULT_SCHEMA. • Sie können Schemas erstellen, die andere Namen haben als Ihr Benutzername, aber Sie können keine Schemas mit den Namen anderer Benutzer erstellen, es sei denn, Sie haben Administratorrechte. • Alle Objekte, die in früheren Versionen von Blackfish SQL erstellt wurden, die Schemas nicht unterstützten, gehören zum Schema DEFAULT_SCHEMA, wenn sie in Version 7 oder höher migriert werden. • Die CREATE SCHEMA-Anweisung wird durch ein Semikolon beendet. Es dürfen sich keine Semikolons zwischen den Schemaelementen befinden. • Alle Anweisungen in der Schemaelementliste werden als eine Anweisung in einer Transaktion ausgeführt. 10 Standardschemas Ihr anfängliches Standardschema ist DEFAULT_SCHEMA. Wenn Sie ein Schema mit dem Namen Ihres aktuellen Benutzernamens erstellen, ist dieses Schema Ihr Standardschema. Sie können Objekte ohne Angabe eines Schemanamens erstellen. Diese Objekte gehören automatisch zu Ihrem Standardschema. Angenommen, der Benutzer PETER hat das Schema PETER erstellt. Dann erstellt PETER eine Tabelle ohne Angabe eines Schemas. Diese Tabelle gehört dann zum Schema PETER. Im folgenden Beispiel würde die erstellte Tabelle PETER.FOO heißen. [USER: PETER] CREATE TABLE FOO (COL1 INT, COL2 VARCHAR); Sie können Schemas erstellen, die andere Namen haben als Ihr Benutzername, aber diese können nicht als Standardschema verwendet werden. Sie können keine Schemas mit den Namen anderer Benutzer erstellen, es sei denn, Sie haben Administratorrechte. 95 Blackfish SQL 10 Syntax <create schema statement> ::= CREATE SCHEMA [ <schema name> ] [ AUTHORIZATION <user name> ] <schema element list> <schema name> ::= <SQL identifier> <schema element commalist> ::= <create table statement> | <create view statement> | <create method statement> | <grant statement> Weitere Informationen zu GRANT-Anweisungen finden Sie unter GRANT . Beispiel Die folgende Anweisung erstellt das Schema BORIS mit einer Tabelle T1 und einer Ansicht V1. Dem Benutzer BERND werden in diesem Schema SELECT-Berechtigungen für die Ansicht V1 gewährt. Nach Ausführung dieser Anweisung ist BORIS das Standardschema für Benutzer BORIS. [USER: BORIS] CREATE SCHEMA BORIS CREATE TABLE T1 (C1 INT, C2 VARCHAR) CREATE VIEW V1 AS SELECT C2 FROM T1 GRANT SELECT ON V1 TO BJORN; DROP SCHEMA Mit der Anweisung DROP SCHEMA wird das angegebene Schema gelöscht. Wenn der Befehl ohne Optionen ausgeführt wird, entspricht dies der Ausführung des Befehls mit der Option RESTRICT: Das zu löschende Schema muss leer sein. Der Befehl schlägt fehl, wenn das Schema Objekte enthält. • Die RESTRICT-Option führt zum Fehlschlagen der Anweisung, wenn sich Objekte im Schema befinden. RESTRICT ist die vorgegebene Option . • In Verbindung mit der CASCADE-Option löscht DROP SCHEMA das benannte Schema einschließlich der Tabellen, Ansichten, Fremdschlüsselabhängigkeiten und Methoden. WARNUNG: Der Befehl DROP SCHEMA ist in Verbindung mit der CASCADE-Option sehr leistungsstark und sollte nur mit Vorsicht verwendet werden. Bei Ausführung dieses Befehls wird das Schema mit allen seinen Objekten und Abhängigkeiten ohne weitere Nachfrage und ohne Möglichkeit zum Rückgängigmachen gelöscht. 10 Tipp:Wenn Sie ein Schema löschen, aber einige seiner Tabellen behalten möchten, verwenden Sie den Befehl ALTER TABLE, um die Tabellen einem anderen Schema zuzuweisen. Beispiel: ALTER TABLE OLDSCHEMA.JOBS RENAME TO NEWSCHEMA.JOBS; Syntax <drop schema statement> ::= DROP SCHEMA <schema name> [ CASCADE | RESTRICT ] Beispiele 1. Die folgenden zwei Anweisungen sind dieselben: sie entfernen das Schema BORIS; sie schlagen beide fehl, wenn das Schema Objekte enthält. DROP SCHEMA BORIS; DROP SCHEMA BORIS RESTRICT; 96 10 Blackfish SQL 2. Folgende Anweisung entfernt das Schema BORIS und alle seine Tabellen, Ansichten und Methoden. Sie entfernt auch alle abhängigen Ansichten und Fremdschlüssel. DROP SCHEMA BORIS CASCADE; CREATE TABLE Die CREATE TABLE-Anweisung erstellt eine Blackfish SQL-Tabelle. Sie müssen für jede Spalte mindestens den Spaltennamen und Datentyp angeben. Optional können Sie für jede Spalte einen Vorgabewert sowie Eindeutigkeitsbegrenzungen festlegen. Sie können auch optional einen Fremd- und einen Primärschlüssel angeben. Blackfish SQL unterstützt die Verwendung von Primär- oder Fremdschlüsseln, die aus einer oder mehreren Spalten gebildet werden können. Schemas angeben Um eine Tabelle in einem bestimmten Schema zu erstellen, geben Sie den Schemanamen als Teil des Tabellennamens an: CREATE TABLE SOMESCHEMA.MYTABLE(. . .); Wenn Sie keinen Schemanamen angeben, wird die Tabelle in Ihrem Standardschema erstellt. Weitere Informationen zu Schemas finden Sie unter CREATE SCHEMA. Datenänderungen für DataExpress protokollieren Anmerkung: Diese Funktion wird nur bei Blackfish SQL für Java unterstützt. Wenn Sie RESOLVABLE als Teil der Tabellendefinition angeben, protokolliert Blackfish SQL Änderungen, die an den Daten vorgenommen werden. Die aufgezeichneten Änderungen stehen der DataExpress-Anwendung zur Verfügung. Sie sind aber nicht für SQL zugänglich. Die Vorgabe ist NOT RESOLVABLE. Konsistenzprüfungen umgehen Die Option NO CHECK erstellt den Fremdschlüssel, ohne die Konsistenz zur Erstellungszeit zu überprüfen. Verwenden Sie die Option mit Vorsicht. AutoIncrement-Spalten mit SQL verwenden Um mit SQL eine Spalte so zu erstellen oder zu ändern, dass sie über eine AutoIncrement-Eigenschaft verfügt, fügen Sie das Schlüsselwort AUTOINCREMENT zu Ihrer <table element>-Definition hinzu. Folgende Anweisung erstellt die Tabelle T1 mit der AutoInkrement-Spalte C1, die den Integer-Datentyp hat: CREATE TABLE T1 ( C1 INT AUTOINCREMENT, C2 DATE, C3 CHAR(32) ); Um den AutoIncrement-Wert einer neu eingefügten Zeile über den JDS-JDBC-Treiber (JVM Version 1.3 oder früher) zu erhalten, rufen Sie die Methode JdsStatement.getGeneratedKeys auf. Diese Methode ist auch in der Anweisungsschnittstelle von JDBC 3 in JVM 1.4 verfügbar.) Spaltenposition angeben Verwenden Sie in der Spaltendefinition die Option POSITION, um zu definieren, dass sich eine Spalte an einer bestimmten Position in der Tabelle (z. B. an zweiter Position) befindet. Der folgende Code-Baustein definiert die Spalte COLD als die zweite Spalte: CREATE TABLE(COLA INT, COLB STRING, COLC INT, COLD STRING POSITION 2); Syntax <create table statement> ::= CREATE TABLE <table name> ( <table element commalist> ) <table name> ::= [ <schema name> . ] <SQL identifier> 97 10 Blackfish SQL 10 <schema name> ::= <SQL identifier> <table element> ::= <column definition> | <primary key> | <unique key> | <foreign key> | [NOT] RESOLVABLE <column definition> ::= <column name> <data type> [ DEFAULT <default value> ] [ [NOT] NULL ] [ AUTOINCREMENT ] [ POSITION <integer literal> ] [ [ CONSTRAINT <constraint name> ] PRIMARY KEY ] [ [ CONSTRAINT <constraint name> ] UNIQUE ] [ [ CONSTRAINT <constraint name> ] <references definition> ] <column name> ::= <SQL identifier> <default value> ::= <literal> | <current date function> <current date function> ::= CURRENT_DATE | CURRENT_TIME | CURRENT_TIMESTAMP <primary key> ::= [ CONSTRAINT <constraint name> ] PRIMARY KEY <column name commalist>) <unique key> ::= [ CONSTRAINT <constraint name> ] UNIQUE ( <column name commalist> ) <foreign key> ::= [ CONSTRAINT <constraint name> ] FOREIGN KEY ( <column name commalist> ) <references definition> <references definition> ::= REFERENCES <table name> [ ( <column name commalist> ) ] [ ON DELETE <action> ] [ ON UPDATE <action> ] [ NO CHECK ] <action> ::= NO ACTION | CASCADE | SET DEFAULT | SET NULL 10 <constraint name> ::= <SQL identifier> Beispiel 1 Folgende Anweisung erstellt eine Tabelle mit vier Spalten. Die Spalte CustId ist der Primärschlüssel und die Spalte OrderDate hat die aktuelle Uhrzeit als Standardwert. CREATE TABLE Orders ( CustId INTEGER PRIMARY KEY, Item VARCHAR(30), Amount INT, OrderDate DATE DEFAULT CURRENT_DATE); Beispiel 2 Die folgende Anweisung erstellt eine Tabelle, die zwei Spalten zur Definition des Primärschlüssels verwendet: CREATE TABLE T1 (C1 INT, C2 STRING, C3 STRING, PRIMARY KEY (C1, C2)); 98 10 Blackfish SQL Beispiel 3 Die folgende Anweisung erstellt die Tabelle T1 im Schema BORIS: CREATE TABLE BORIS.T1 (C1 INT, C2 STRING, C3 STRING); ALTER TABLE Die ALTER TABLE-Anweisung führt folgende Operationen durch: • Hinzufügen oder Entfernen von Spalten einer Blackfish SQL-Tabelle • Setzen oder Entfernen von Spaltenstandards und die Möglichkeit, dass die Spalte keine Wert (NULL) besitzt • Ändern von Spalten-Datentypen • Hinzufügen oder Entfernen von Spaltenbegrenzungen für Primärschlüssel, eindeutige Schlüssel und Fremdschlüssel sowie von Tabellenbegrenzungen; ändert die referenzierte Tabelle und die Art der Aktion für diese Begrenzungen • Umbenennen von Spalten • Umbenennen von Tabellen; ermöglicht auch das Verschieben von Tabellen von einem Schema in ein anderes • Hinzufügen oder Entfernen der Tabelleneigenschaft RESOLVABLE • Ändern der Spaltenposition in der Tabelle Syntax <alter table statement> ::= ALTER TABLE <table name> <change definition commalist> <table name> ::= [ <schema name> . ]<SQL identifier> <change definition> ::= <add column element> | <drop column element> | <alter column element> | <add constraint> | <drop constraint> | [RENAME] TO <table name> | [NOT] RESOLVABLE <add column element> ::= ADD [COLUMN] <column definition> <column definition> ::= <column name> <data type> [ [NOT] NULL ] [ AUTOINCREMENT ] [ POSITION <integer literal> ] [ [ CONSTRAINT <constraint name> [ [ CONSTRAINT <constraint name> [ [ CONSTRAINT <constraint name> [ DEFAULT <default value> ] ] PRIMARY KEY ] ] UNIQUE ] ] <references definition> ] 10 <drop column element> ::= DROP [COLUMN] <column name> <alter column element> ::= ALTER [COLUMN] <column name> [TYPE] <data type> | ALTER [COLUMN] <column name> SET DEFAULT <default-value> | ALTER [COLUMN] <column name> DROP DEFAULT | ALTER [COLUMN] <column name> [NOT] NULL | ALTER [COLUMN] <column name> [RENAME] TO <column name> | ALTER [COLUMN] <column name> [POSITION] <integer literal> | ALTER [COLUMN] <column name> AUTOINCREMENT | ALTER [COLUMN] <column name> DROP AUTOINCREMENT <add constraint> ::= ADD <base table constraint> <base table constraint> ::= 99 Blackfish SQL <primary key> | <unique key> | 10 <foreign key> <drop constraint> ::= DROP CONSTRAINT <constraint name> <primary key> ::= [ CONSTRAINT <constraint name> ] PRIMARY KEY <column name commalist>) <unique key> ::= [ CONSTRAINT <constraint name> ] UNIQUE ( <column name commalist> ) <foreign key> ::= [ CONSTRAINT <constraint name> ] FOREIGN KEY ( <column name commalist> ) <references definition> <references definition> ::= REFERENCES <table name> [ ( <column name commalist> ) ] [ ON DELETE <action> ] [ ON UPDATE <action> ] [ NO CHECK ] <action> ::= NO ACTION | CASCADE | SET DEFAULT | SET NULL <constraint name> ::= <SQL identifier> In ALTER [COLUMN] wird das optionale COLUMN-Schlüsselwort nur aus Gründen der SQL-Kompatibilität aufgeführt. Es hat keine Bedeutung. Beispiel Im folgenden Beispiel wird eine Spalte namens ShipDate zur Orders-Tabelle hinzugefügt und die Spalte Amount aus der Tabelle entfernt. ALTER TABLE Orders ADD ShipDate DATE, DROP Amount; Im folgenden Beispiel wird die Tabelle Jobs aus dem Schema OldSchema in das Schema NewSchema verschoben. ALTER TABLE OldSchema.Jobs RENAME TO NewSchema.Jobs; 10 DROP TABLE Mit der DROP TABLE-Anweisung werden Tabellen und die zugehörigen Indizes aus Blackfish SQL-Datenbanken gelöscht. • Die RESTRICT-Option stellt sicher, dass die Anweisung fehlschlägt, wenn für die Tabelle Fremdschlüssel- oder Ansichtsabhängigkeiten gelten. • Die CASCADE-Option sorgt dafür, dass beim Entfernen der Tabelle alle abhängigen Ansichten und Fremdschlüssel entfernt werden. • Wenn weder RESTRICT noch CASCADE angegeben wird, wird die Tabelle entfernt und mit ihr alle Fremdschlüssel, die sie referenzieren. Die Anweisung schlägt fehl, wenn abhängige Ansichten vorhanden sind. Syntax <drop table statement> ::= DROP TABLE [ <schema name> . ]<table name> [ CASCADE|RESTRICT ] 100 10 Blackfish SQL <schema name> ::= <SQL identifier> Beispiele 1. Folgende Anweisung entfernt die Orders-Tabelle nur, wenn keine abhängigen Ansichten vorhanden sind. Gibt es abhängige Fremdschlüssel, werden diese entfernt. DROP TABLE Orders; 2. Folgende Anweisung entfernt die Orders-Tabelle nur, wenn keine abhängigen Ansichten oder Fremdschlüssel vorhanden sind. DROP TABLE Orders RESTRICT; 3. Folgende Anweisung entfernt die Orders-Tabelle. Alle abhängigen Ansichten und Fremdschlüssel werden ebenfalls entfernt. DROP TABLE Orders CASCADE; CREATE VIEW Mit der Anweisung CREATE VIEW wird eine abgeleitete Tabelle durch Auswählen bestimmter Spalten aus vorhandenen Tabellen erstellt. Ansichten stellen eine Möglichkeit dar, auf eine konsistente Teilmenge der Daten einer oder mehrerer Tabellen zuzugreifen. Änderungen an den Daten in den zugrunde liegenden Tabellen werden auch in der Ansicht angezeigt. Ansichten sehen wie Datenbanktabellen aus, aber die in der Ansicht angezeigten Daten sind nicht extra in der Datenbank gespeichert. In der Datenbank ist lediglich die Definition der Ansicht gespeichert. Diese Definition wird verwendet, um die benötigten Daten zu filtern, wenn eine Abfrage ausgeführt wird, die sich auf die Ansicht bezieht. Wenn Sie eine Ansicht erstellen, können Sie die Namen der Spalten in der Ansicht mit dem optionalen Teil <column name commalist> der Syntax angeben. Wenn Sie keine Spaltennamen angeben, werden die Namen der Tabellenspalten verwendet, von denen die Ansichtsspalten abgeleitet sind. Wenn Sie Spaltennamen angeben, müssen Sie die Anzahl der Spalten exakt angeben, die von der SELECT-Abfrage zurückgeliefert werden. Die Klausel WITH CHECK OPTION dient zur Überprüfung während der Laufzeit, um sicherzustellen, dass eine eingefügte oder aktualisierte Zeile nicht von der WHERE-Klausel der Ansichtsdefinition ausgefiltert wird. Ansichten sind nur unter bestimmten Bedingungen aktualisierbar. Wenn Sie INSERT, UPDATE oder DELETE auf eine Ansicht ausführen möchten, muss diese folgende Bedingungen erfüllen: • Sie leitet sich aus einer einzigen Tabelle ab. • Keine der Spalten darf eine berechnete Spalte sein. • Die SELECT-Klausel, die die Ansicht definiert, darf das Schlüsselwort DISTINCT nicht enthalten. • Der SELECT-Ausdruck, der die Ansicht definiert, darf Folgendes nicht enthalten: • Unterabfragen 10 • Eine HAVING-Klausel • Eine GROUP BY-Klausel • Eine ORDER BY-Klausel • Aggregatfunktionen • Methoden Syntax <create view statement> ::= CREATE VIEW <view name> [ ( <column name commalist> ) ] AS <select expression> [ WITH CHECK OPTION ] <view name> ::= [ <schema name> . ]<SQL identifier> 101 Blackfish SQL 10 Beispiel Folgende Anweisung erstellt die Ansicht V1 aus der Tabelle T1. Die Spalten in der Ansicht heißen C1 und C2. CREATE VIEW V1(C1,C2) AS SELECT C8+C9, C6 FROM T1 WHERE C8 < C9; ALTER VIEW Mit der Anweisung ALTER VIEW wird eine Ansicht geändert, ohne dass abhängige Ansichten und vorhandene GRANTs verloren gehen. Diese Anweisung kann verwendet werden, um den Namen oder die Zusammensetzung der Spalten der Ansicht zu ändern und um festzulegen, ob die Begrenzung WITH CHECK OPTION für die Ansicht gilt. Beachten Sie, dass es nach der Ausführung von ALTER VIEW noch abhängige Ansichten gibt, die nicht mehr gültig sind. Syntax <alter view statement> ::= ALTER VIEW <view name> [ ( <column name commalist> ) ] AS <select expression> [ WITH CHECK OPTION ] Beispiel Folgende Anweisungen verdeutlichen, wie die ALTER VIEW-Anweisung zum Validieren einer ungültigen Ansicht verwendet werden kann. Mit den ersten zwei Anweisungen wird eine Tabelle und dann, basierend auf der Tabelle, eine Ansicht erstellt. Mit der dritten Anweisung (SELECT) wird dann die Abfrage ausgeführt. CREATE TABLE T1 (C1 INT, C2 VARCHAR); CREATE VIEW V1 AS SELECT C1, C2 FROM T1; SELECT * FROM V1; Mit der folgenden Anweisung wird ein Spaltenname in der Tabelle geändert. ALTER TABLE T1 ALTER COLUMN C1 RENAME TO ID; Die nachfolgende SELECT-Anweisung wird fehlschlagen, weil es keine Spalte C1 mehr in der Tabelle T1 gibt, auf der die Ansicht V1 basiert. SELECT * FROM V1; Mit folgender ALTER VIEW-Anweisung wird die Definition der Ansicht geändert, damit die darauf folgende SELECT-Anweisung erfolgreich ausgeführt werden kann. ALTER VIEW V1 (C1, C2) AS SELECT ID, C2 FROM T1; SELECT * FROM V1; 10 DROP VIEW Mit der Anweisung DROP VIEW wird die angegebene Ansicht gelöscht. Die Anweisung schlägt fehl, wenn die Ansicht über Abhängigkeiten verfügt. • Die RESTRICT-Option hat dieselben Folgen, als würden keine Optionen angegeben: die Anweisung schlägt fehl, wenn die Ansicht über Abhängigkeiten verfügt. • Mit der Option CASCADE werden die Ansicht und alle abhängigen Ansichten gelöscht. Syntax <drop view statement> ::= DROP VIEW <view name> [ CASCADE | RESTRICT ] Beispiel 102 10 Blackfish SQL Mit folgendem Code werden eine Tabelle und zwei Ansichten erstellt: CREATE TABLE T1 (C1 INT, C2 VARCHAR); CREATE VIEW V1 AS SELECT C1, C2 FROM T1; CREATE VIEW V2 AS SELECT C1, C2 FROM V1; Folgende Anweisung schlägt fehl, weil die Ansicht V1 eine abhängige Ansicht (V2) hat. DROP VIEW V1 RESTRICT; Folgende Anweisung wird erfolgreich ausgeführt, wobei die Ansichten V1 und V2 entfernt werden. DROP VIEW V1 CASCADE; CREATE INDEX Mit der CREATE INDEX-Anweisung wird ein Index für eine Blackfish SQL-Tabelle erstellt. Für jede Spalte kann eine Sortierung in aufsteigender oder absteigender Reihenfolge festgelegt werden. Der Vorgabewert ist aufsteigende Reihenfolge. Syntax <create index statement> ::= CREATE [UNIQUE] [CASEINSENSITIVE] INDEX <index name> ON <table name> ( <index element commalist> ) <table name> ::= [ <schema name> . ]<SQL identifier> <index name> ::= <SQL Identifier> <index element> ::= <column name> [ DESC|ASC ] Beispiel Mit der folgenden Anweisung wird für die ITEM-Spalte der ORDERS-Tabelle ein nicht eindeutiger, aufsteigender Index mit Unterscheidung zwischen Groß- und Kleinschreibung erstellt: CREATE INDEX OrderIndex ON Orders (Item ASC); DROP INDEX Mit der DROP INDEX-Anweisung wird ein Index für eine Blackfish SQL-Tabelle gelöscht. Syntax 10 <drop index statement> ::= DROP INDEX <index name> ON <table name> Beispiel Mit der folgenden Anweisung wird der Index "OrderIndex" der Tabelle "Orders" gelöscht: DROP INDEX OrderIndex ON Orders; CREATE METHOD Die CREATE METHOD-Anweisung stellt eine gespeicherte Prozedur oder eine in Java oder einer .NET-Sprache (e.g., Delphi, C#, or VB.NET) implementierte benutzerdefinierte Funktion zur Verwendung in Blackfish SQL bereit. Zuvor müssen jedoch die Klassendateien für den Code zum Klassenpfad des Blackfish SQL-Server-Prozesses hinzugefügt werden. Unter "Benutzerdefinierte Funktionen und gespeicherte Prozeduren" finden Sie weitere Informationen über die Implementierung 103 Blackfish SQL 10 gespeicherter Prozeduren und benutzerdefinierter Funktionen (UDFs) für Blackfish SQL. Um eine Methode in einem bestimmten Schema zu erstellen, geben Sie den Schemanamen als Teil des Tabellennamens an: CREATE METHOD SOMESCHEMA.MYMETHOD AS . . . Wenn Sie keinen Schemanamen angeben, wird die Methode wie folgt einem Schema zugewiesen:. • Wenn Sie ein persönliches Standardschema erstellt haben (ein Schema mit demselben Namen wie Ihr Benutzername), wird die Methode in diesem Schema erstellt. • Wenn Sie kein persönliches Standardschema erstellt haben, gehört die Methode zum Schema DEFAULT_SCHEMA. Weitere Informationen zu Schemas finden Sie unter CREATE SCHEMA. Die AUTHORIZATION-Klausel ermöglicht, dass die aufgerufene gespeicherte Prozedur so ausgeführt wird, als ob der Benutzername in der AUTHORIZATION-Klausel der Name des aktuellen Benutzers wäre. Wird die Klausel weggelassen, wird current_user als aktueller Benutzer für Methodenaufrufe verwendet. Diese Funktion ermöglicht dem aktuellen Benutzer kontrollierten Zugriff auf Tabellen und Ansichten, auf die anderenfalls nicht zugegriffen werden könnte. Syntax <create method statement> ::= CREATE METHOD <method name> [AUTHORIZATION <username>] AS <method definition> <method name> ::= [ <schema name> . ] <SQL identifier> <schema name> ::= <SQL identifier> <method definition> ::= <string literal> Beispiel CREATE METHOD ABS AS 'MathClass.abs'; DROP METHOD Mit der DROP METHOD-Anweisung wird eine gespeicherte Prozedur oder eine benutzerdefinierte Funktion entfernt, sodass sie nicht mehr in der Blackfish SQL verwendet werden kann. Syntax <drop method statement> ::= DROP METHOD <method_name> Beispiel DROP METHOD ABS; 10 CREATE CLASS Die CREATE CLASS-Anweisung ermöglicht die Bereitstellung aller öffentlichen, statischen Methoden einer Klasse für Blackfish SQL in Form von gespeicherten Prozeduren oder benutzerdefinierten Funktionen (UDFs). Es wird dabei vorausgesetzt, dass sich die Klassendateien für den Code im Klassenpfad des Blackfish SQL-Serverprozesses befinden. Weitere Informationen hierzu finden Sie im Kapitel Gespeicherte Prozeduren und UDFs. Die AUTHORIZATION-Klausel ermöglicht, dass die aufgerufene gespeicherte Prozedur so ausgeführt wird, als ob der Benutzername in der AUTHORIZATION-Klausel der Name des aktuellen Benutzers wäre. Wird die Klausel weggelassen, wird current_user als aktueller Benutzer für Methodenaufrufe verwendet. Diese Funktion ermöglicht dem aktuellen Benutzer kontrollierten Zugriff auf Tabellen und Ansichten, auf die anderenfalls nicht zugegriffen werden könnte. Syntax 104 10 Blackfish SQL <create class statement> ::= CREATE CLASS <class name> [AUTHORIZATION <username>] AS <class definition> <class name> ::= [ <schema name> . ] <SQL identifier> <schema name> ::= <SQL identifier> <class definition> ::= <string literal> Beispiele CREATE CLASS MATH AS 'mscorlib::System.Math'; Nach Ausführung der obigen Anweisung können alle öffentlichen, statischen Methoden in System.Math von SQL aus aufgerufen werden. Bei Methodennamen muss die Groß-/Kleinschreibung beachtet werden. Verwendung Folgende Anweisung ruft die abs()-Methode in System.Math auf: SELECT * FROM CUSTOMER WHERE MATH."Abs"(AGE - 50) < 5; DROP CLASS Mit der DROP CLASS-Anweisung wird eine gespeicherte Klasse entfernt, sodass sie nicht mehr in der Blackfish SQL verwendet werden kann. Syntax <drop class statement> ::= DROP CLASS <method_name> Beispiel DROP CLASS MATH; CREATE TRIGGER Die CREATE TRIGGER-Anweisung erstellt einen Trigger auf Zeilenebene für eine Tabelle. Sie müssen sicherstellen, dass die Klassen vom Blackfish SQL-Server-Prozess geladen werden können. Unter Trigger in Blackfish SQL-Tabellen verwenden finden Sie weitere Details zum Implementieren von Trigger-Methoden und zum Sicherstellen, dass die Methodenklassen geladen werden können. 10 Syntax create trigger statement> ::= CREATE TRIGGER <trigger name> <trigger action time> <trigger action name> ON <table name> AS <trigger spec> <trigger name> ::= <SQL identifier> <tablename> ::= <SQL identifier> <triggeraction time> ::= <BEFORE | AFTER> <trigger action name> ::= <INSERT | UPDATE | DELETE > 105 Blackfish SQL 10 Blackfish SQL für Java: <trigger spec> ::= "[<package>.]<class-name>.<method-name>" Blackfish SQL für Windows: <trigger spec> ::="<assembly-name>::[<name-space>.]<class-name>.<method-name>" Beispiele Blackfish SQL für Windows: CREATE TRIGGER VALIDATE_CUSTOMER BEFORE INSERT ON CUSTOMER AS OrderEntryAssembly::OrderEntry.Customers.ValidateCustomer Blackfish SQL für Java: CREATE TRIGGER VALIDATE_CUSTOMER BEFORE INSERT ON CUSTOMER AS OrderEntry.Customers.validateCustomer DROP TRIGGER Mit der DROP TRIGGER-Anweisung wird ein Trigger entfernt, sodass er nicht mehr in der Blackfish SQL verwendet werden kann. Syntax <drop trigger statement> ::= DROP TRIGGER <trigger name> ON <table name> <trigger name> ::= <SQL identifier> <table name> ::= <SQL identifie Beispiel DROP TRIGGER VALIDATE_CUSTOMER on CUSTOMER Anweisungen zur Transaktionssteuerung 10 COMMIT Mit der COMMIT-Anweisung wird die aktuelle Transaktion bestätigt. Sie ist nur wirksam, wenn die AUTOCOMMIT-Funktion deaktiviert ist. Syntax <commit statement> ::= COMMIT [WORK] ROLLBACK Mit der ROLLBACK-Anweisung wird die aktuelle Transaktion rückgängig gemacht. Diese Anweisung wird nicht wirksam, wenn AUTOCOMMIT aktiviert ist. 106 10 Blackfish SQL Syntax <rollback statement> ::= ROLLBACK [WORK] SET AUTOCOMMIT Mit der SET AUTOCOMMIT-Anweisung wird der Autocommit-Modus geändert. Autocommit ist anfänglich ON, wenn eine JDBC-Verbindung erstellt wird. Der Autocommit-Modus kann auch über die JDBC-Connection-Instanz festgelegt werden. Syntax <set autocommit statement> ::= SET AUTOCOMMIT { ON | OFF }; SET TRANSACTION Mit der SET TRANSACTION-Anweisung können die Eigenschaften für die folgende Transaktion eingestellt werden. Sie können damit die Isolationsebene angeben und festlegen, ob es sich um eine Transaktion zum Lesen und Schreiben oder nur zum Lesen handelt. Unter Systemarchitektur finden Sie Informationen zum Blackfish SQL-Transaktionsmanagement. Dieser Befehl muss ausgeführt werden, wenn es keine offene Transaktion gibt. Er gilt nur für die nächste Transaktion und startet selbst keine Transaktion. Zum Verständnis von Isolationsebenen sollten Sie mit den folgenden Begriffen vertraut sein: • Dirty Read - tritt auf, wenn eine Zeile, die von einer Transaktion geändert wird, von einer anderen Transaktion gelesen wird, bevor die Änderungen festgeschrieben (committed) wurden. • Non-Repeatable Read - tritt auf, wenn eine Transaktion eine Zeile liest, eine zweite Transaktion die Zeile ändert und die erste Transaktion die Zeile neu liest und dabei andere Werte erhält als beim ersten Lesevorgang. • Phantom Read - tritt auf, wenn eine Transaktion alle Zeilen liest, die einer WHERE-Bedingung entsprechen, eine zweite Transaktion eine Zeile einfügt, die der WHERE-Bedingung entspricht und die erste Transaktion mit derselben Bedingung neu liest und dabei die zusätzliche "Phantomzeile" abruft. Blackfish SQL bietet folgende Ebenen der Transaktionsisolation: TRANSACTION_READ_UNCOMMITTED erlaubt Dirty Reads, Non-Repeatable Reads und Phantom Reads. Wenn Änderungen rückgängig gemacht werden (Rollback), ist die von der zweiten Transaktion abgerufene Zeile ungültig. Auf dieser Isolationsebene werden keine Zeilensperrungen für Lesevorgänge angefordert. Außerdem werden exklusive Zeilensperrungen nicht berücksichtigt, die von anderen Verbindungen nach dem Einfügen oder Aktualisieren einer Zeile aufrechterhalten werden. TRANSACTION_READ_COMMITTED verhindert Dirty Reads; Non-Repeatable Reads und Phantom Reads sind dagegen zulässig. Auf dieser Ebene sind nur die Transaktionen unzulässig, die auf eine Zeile zugreifen möchten, die noch nicht festgeschriebene ("uncommitted") Änderungen enthält. Auf dieser Isolationsebene werden keine Zeilensperrungen für Lesevorgänge angefordert. Das Lesen einer Zeile, die von einer anderen Transaktion exklusiv gesperrt ist, wird aber verhindert. TRANSACTION_REPEATABLE_READ verhindert Dirty Reads und Non-Repeatable Reads; Phantom Reads sind dagegen zulässig. Auf dieser Ebene werden gemeinsam genutzte Zeilensperrungen für Lesevorgänge angefordert. Diese Ebene bietet konsistenten Datenzugriff für Transaktionen ohne die eingeschränkte Concurrency von TRANSACTION_SERIALIZABLE, hat aber erhöhten Sperr-Overhead zur Folge. TRANSACTION_SERIALIZABLE bietet eine vollständige Serialisierung der Transaktionen, hat aber eingeschränkte Concurrency und ein erhöhtes Deadlock-Risiko zur Folge. Syntax 107 10 Blackfish SQL 10 <set transaction statement> ::= SET TRANSACTION <transaction option commalist> <transaction option> ::= READ ONLY | READ WRITE | ISOLATION LEVEL <isolation level> <isolation level> ::= READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE Beispiel Im folgenden Beispiel wird das Select von T1 zu einem Dirty Read, d. h., dass die Daten von einem anderen Benutzer noch nicht festgeschrieben wurden. Nach dem zweiten COMMIT erhält die Isolationsebene den Status, der für die Sitzung angegeben wurde. COMMIT; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM T1; COMMIT; Anweisungen zur Datenmanipulation SELECT Mit einer SELECT-Anweisung können Daten aus einer oder mehreren Tabellen abgerufen werden. Das optionale Schlüsselwort DISTINCT entfernt doppelte Zeilen in der Ergebnismenge. Das ALL-Schlüsselwort (Vorgabe) gibt alle Zeilen einschließlich der doppelten Zeilen zurück. Bei Bedarf können die Daten auch mit ORDER BY sortiert werden. Die abgerufenen Zeilen können bei Bedarf für ein anstehendes UPDATE mittels FOR UPDATE gesperrt werden. Syntax <select statement> ::= <table expression> [ ORDER BY <order item list> ] [ FOR UPDATE|FOR READ ONLY ] 10 <table expression> ::= <table expression> UNION [ALL] <table expression> | <table expression> EXCEPT [ALL] <table expression> | <table expression> INTERSECT [ALL] <table expression> | <join expression> | <select expression> | ( <table expression> ) <order item> ::= <order part> [ ASC|DESC ] <order part> ::= <integer literal> | <column name> | <expression> <select expression> ::= SELECT [ ALL|DISTINCT ] <select item commalist> FROM <table reference commalist> [ WHERE <conditional expression> ] [ GROUP BY <column reference commalist> ] [ HAVING <conditional expression> ] Beispiele Die folgende Anweisung sortiert die Ausgabe nach der ersten Spalte in absteigender Reihenfolge. 108 10 Blackfish SQL SELECT Item FROM Orders ORDER BY 1 DESC; Die folgende Anweisung sortiert nach der berechneten Spalte CALC: SELECT CustId, Amount*Price+500.00 AS CALC FROM Orders ORDER BY CALC; Die nächste Anweisung sortiert die Ausgabe nach dem Ausdruck Amount*Price: SELECT CustId, Amount FROM Orders ORDER BY Amount*Price; SELECT INTO SELECT INTO ist eine SELECT-Anweisung, die genau eine Zeile ausgibt, deren Werte in Form von Ausgabeparametern abgerufen werden. Wenn die SELECT-Anweisung mehr als eine Zeile oder einen leeren Ergebnissatz ergibt, ist dies ein Fehler. Syntax <single row select statement> ::= SELECT [ ALL|DISTINCT ] <select item commalist> INTO <parameter commalist> FROM <table reference commalist> [ WHERE <conditional expression> ] [ GROUP BY <column reference commalist> ] [ HAVING <conditional expression> ] Beispiel In der folgenden Anweisung kennzeichnen die ersten beiden Parametermarkierungen Ausgabeparameter, aus denen das Ergebnis der Abfrage abgerufen werden kann: SELECT CustId, Amount INTO ?, ? FROM Orders WHERE CustId=? ; INSERT Mit der INSERT-Anweisung werden Zeilen in eine Tabelle einer Blackfish SQL-Datenbank eingefügt. Mit der INSERT-Anweisung werden Spalten und die zugehörigen Werte aufgelistet. Spalten, die nicht in der Anweisung angegeben sind, werden auf ihre Standardwerte gesetzt. Syntax 10 <insert statement> ::= [ SELECT AUTOINCREMENT FROM ] INSERT INTO <table name> [ ( <column name commalist> ) ] [ <insert table expression>|DEFAULT VALUES ] <table name> ::= [ <schema name> . ]<SQL identifier> <insert table expression> ::= <select expression> | VALUES ( <expression commalist> ) Beispiel 1 Bei jeder Ausführung der folgenden Anweisung wird eine Zeile eingefügt. Bei jeder Ausführung wird eine Zeile eingefügt. Die nicht in der Anweisung angegebenen Spalten werden auf ihre Standardwerte gesetzt. Besitzt eine Spalte keinen Standardwert, wird sie auf NULL gesetzt. 109 Blackfish SQL 10 INSERT INTO Orders (CustId, Item) VALUES (?,?); Beispiel 2 Diese Anweisung findet alle Bestellungen des Kunden mit der CustId von 123 und fügt den zu diesen Bestellungen gehörenden Artikel (Item) in die Tabelle ResTable ein. INSERT INTO ResTable SELECT Item FROM Orders WHERE CustId = 123; Beispiel 3 Bei jeder Ausführung der folgenden Anweisung wird eine Zeile eingefügt. In diesem Fall ist die CustId-Spalte der Orders-Tabelle nicht angegeben. Es wird angenommen, dass CustId eine AUTOINCREMENT-Spalte ist, für die die SQL-Engine automatisch einen inkrementierten Wert generiert. In diesem Beispiel ist SELECT AUTOINCREMENT FROM angegeben, wodurch der generierte Wert als eine Ergebnismenge zurückgegeben wird. Wenn die Orders-Tabelle keine AUTOINCREMENT-Spalte enthält, besteht die Ergebnismenge aus den INTERNALROW-Werten für die eingefügten Zeilen. SELECT AUTOINCREMENT FROM INSERT INTO Orders (Item) VALUES (?) UPDATE Die UPDATE-Anweisung wird zum Ändern vorhandener Daten verwendet. Die zu ändernden Spalten werden explizit aufgelistet. Alle Zeilen, bei denen die WHERE-Klausel TRUE ausgibt, werden geändert. Wird keine WHERE-Klausel angegeben, werden alle Zeilen in der Tabelle geändert. Syntax <update statement> ::= UPDATE <table name> SET <update assignment commalist> [ WHERE <conditional expression> ] <table name> ::= [ <schema name> . ] <SQL identifier> <update assignment> ::= <column reference> = <update expression> <update expression> ::= <scalar expression> | DEFAULT | NULL Beispiel 1 10 Mit der folgenden Anweisung werden alle Bestellungen von Kunde 123 in Bestellungen von Kunde 500 geändert: UPDATE Orders SET CustId = 500 WHERE CustId = 123; Beispiel 2 Mit der folgenden Anweisung wird die Anzahl an Bestellungen in der Tabelle um 1 erhöht: UPDATE Orders SET Amount = Amount + 1; Beispiel 3 Mit der folgenden Anweisung wird der Preis aller Unterwasser-Einwegkameras auf 7,25 $ geändert: UPDATE Orders SET Price = 7.25 WHERE Price > 7.25 AND Item = 'UWCamaras'; 110 10 Blackfish SQL DELETE Mit der DELETE-Anweisung werden Zeilen aus einer Tabelle der Blackfish SQL-Datenbank gelöscht. Wird keine WHERE-Klausel angegeben, werden alle Zeilen gelöscht. Ansonsten werden nur die Zeilen gelöscht, die dem WHERE-Ausdruck entsprechen. Syntax <delete statement> ::= DELETE FROM <table name> [ WHERE <conditional expression> ] <table name> ::= [ <schema name> . ]<SQL identifier> Beispiel Mit der folgenden Anweisung werden alle Bestellungen für Shorts aus der Orders-Tabelle gelöscht. DELETE FROM Orders WHERE Item = 'Shorts'; CALL Die CALL-Anweisung ruft eine gespeicherte Prozedur auf. Syntax <call statement> ::= [ ? = ] CALL <method name> ( <expression commalist> ) Beispiel 1 Die Parametermarkierung gibt die Position der Ausgabeparameter an, aus denen das Abfrageergebnis der gespeicherten Prozedur abgerufen werden kann. ?=CALL ABS(-765); Beispiel 2 Die Methode, die IncreaseSalaries implementiert, aktualisiert die Tabelle salaries mit einem prozentualen Zuwachs für alle Mitarbeiter. Ein Verbindungsobjekt wird implizit an die Methode übergeben. Für alle von IncreaseSalaries betroffenen Zeilen wird von Statement.executeUpdate ein updateCount zurückgegeben. CALL IncreaseSalaries(10); LOCK TABLE Die LOCK TABLE-Anweisung sperrt eine Tabelle explizit. Die Sperre wird erst aufgehoben, wenn eine Transaktion bestätigt oder rückgängig gemacht wird. Syntax <lock statement> ::= `LOCK <table name commalist> <table name> ::= [ <schema name> . ]<SQL identifier> Beispiel Mit der folgenden Anweisung werden die Tabellen Orders und LineItems gesperrt. LOCK Orders, LineItems; Sicherheitsanweisungen 111 10 Blackfish SQL 10 CREATE USER Die CREATE USER-Anweisung fügt den Benutzernamen und das zugehörige Passwort zur Datenbank hinzu. Nur ein Administrator kann Benutzer erstellen. Anmerkung: Beim Passwort muss die Groß-/Kleinschreibung immer beachtet werden. Beim Benutzernamen muss die Groß-/Kleinschreibung nicht beachtet werden. Ein neu erstellter Benutzer hat standardmäßig alle Datenbankberechtigungen außer ADMINISTRATOR. Sie haben die Berechtigungen STARTUP, WRITE, CREATE, DROP, CREATE ROLE und CREATE SCHEMA. Wenn Sie einem Benutzer bestimmte Berechtigungen entziehen möchten, verwenden Sie REVOKE. Syntax <create user statement> ::= CREATE USER <user name> PASSWORD <SQL identifier> Beispiel CREATE USER jmatthews PASSWORD "@nyG00dPas2d"; ALTER USER Mit der ALTER USER-Anweisung wird das neue Passwort für einen vorhandenen Benutzer festgelegt. Nur ein Administrator oder ein benannter Benutzer kann das Passwort ändern. Anmerkung: Das Passwort, das Sie eingeben, wird in Großbuchstaben gespeichert, es sei denn, sie schließen das Passwort in doppelte Anführungszeichen ein. Es wird empfohlen, dass Sie das Passwort immer in doppelte Anführungszeichen einschließen. Syntax <alter user statement> ::= ALTER USER <user name> SET PASSWORD <SQL identifier> Beispiel ALTER USER GSMITH SET PASSWORD "usethisOnen0w"; DROP USER Mit der DROP USER-Anweisung werden ein Benutzer und alle Objekte, die er besitzt, entfernt. 10 • In Verbindung mit RESTRICT bzw. ohne Option schlägt die Anweisung fehl, wenn der Benutzer Eigentümer von Objekten wie beispielsweise Tabellen, Ansichten oder Methoden ist. • In Verbindung mit CASCADE werden der Benutzer und alle Objekte, die er besitzt, entfernt. Syntax <drop user statement> ::= DROP USER <user name> [ CASCADE|RESTRICT ] Beispiel Mit der folgenden Anweisung werden der Benutzer gsmith und alle Tabellen, Ansichten und Methoden, die er besitzt, entfernt. DROP USER gsmith CASCADE; CREATE ROLE Mit der Anweisung CREATE ROLE wird eine bezeichnete Rolle erstellt. 112 10 Blackfish SQL Die Verwendung von Rollen geschieht in vier Schritten: • Erstellen Sie eine Rolle mit der CREATE ROLE-Anweisung. • Gewähren Sie der Rolle Zugriffsrechte mit der GRANT-Anweisung. • Weisen Sie die Rolle einem oder mehreren Benutzern mit der GRANT-Anweisung zu. Dadurch ist der Benutzer autorisiert, diese Rolle zu verwenden. • Ein autorisierter Benutzer kann auf die Zugriffsrechte, die einer Rolle gewährt wurden, mit der SET ROLE-Anweisung zugreifen. Um eine Rolle zu erstellen, muss der Benutzer die Systemberechtigung CREATE ROLE haben. Alle Benutzer verfügen standardmäßig über diese Berechtigung, aber sie kann explizit entzogen werden. Syntax <create role statement> ::= CREATE ROLE <role name> Beispiel CREATE ROLE salesperson; SET ROLE Mit der Anweisung SET ROLE wird eine bezeichnete Rolle aktiviert. Der aktuelle Benutzer erhält alle Berechtigungen, die dieser Rolle zugewiesen wurden. Verwenden Sie SET ROLE NONE, um die aktuelle Rolle zu deaktivieren, ohne eine andere Rolle zu aktivieren. Anmerkung: Dieser Befehl muss ausgeführt werden, wenn es keine aktive Transaktion gibt. Die Rolle ist bis zum Ende der Sitzung oder bis zur Ausführung eines neuen SET ROLE-Befehls aktiv. Syntax <set role statement> ::= SET ROLE <role specification> <role specification> ::= NONE | <role name> Beispiel Mit der folgenden Anweisung wird die Manager-Rolle aktiviert: SET ROLE Manager; Mit der folgenden Anweisung wird die aktive Rolle deaktiviert und keine neue Rolle aktiviert: SET ROLE NONE; 10 DROP ROLE Mit der DROP ROLE-Anweisung wird die angegebene Rolle entfernt. • Wenn DROP ROLE in Verbindung mit CASCADE verwendet wird, werden alle Zugriffsrechte entzogen, die mittels dieser Rolle gewährt wurden. • Wenn DROP ROLE in Verbindung mit RESTRICT verwendet wird, schlägt die Anweisung fehl, wenn die Rolle zu diesem Zeitpunkt einem Benutzer oder einer Rolle zugewiesen ist. • Die Verwendung von DROP ROLE ohne eine Option ist identisch mit DROP ROLE in Verbindung mit RESTRICT. Syntax <drop role statement> ::= 113 Blackfish SQL 10 DROP ROLE <role name> [ CASCADE|RESTRICT ] Beispiel Mit der folgenden Anweisung wird die Rolle Sales entfernt. Alle Zugriffsrechte, die Benutzern oder anderen Rollen durch die Sales-Rolle gewährt wurden, werden entzogen. DROP ROLE Sales CASCADE; GRANT Die GRANT-Anweisung führt die folgenden drei Aktionen durch: • Sie gewährt PUBLIC, Benutzern oder Rollen Objektberechtigungen wie beispielsweise INSERT oder SELECT auf Tabellen oder Methoden. • Sie gewährt Benutzern oder Rollen Datenbankberechtigungen (beispielsweise STARTUP oder RENAME). • Sie weist die Rollen Benutzern oder anderen Rollen zu. GRANT-Optionen: • Wenn mit der Option GRANT Objektberechtigungen gewährt wurden, kann der Berechtigte diese gewährten Objektberechtigungen an andere Benutzer weitergeben. • Wenn mit der Option ADMINISTRATOR Datenbankberechtigungen oder Rollen gewährt wurden, kann der Berechtigte diese gewährten Datenbankberechtigungen oder Rollen an andere Benutzer weitergeben. • Die Datenbankberechtigung ADMINISTRATOR gewährt die Rechte STARTUP, WRITE, CREATE, DROP, RENAME, CREATE ROLE und CREATE SCHEMA. Wenn diese Berechtigungen durch ADMINISTRATOR erworben wurden, können sie auch nur durch das Entziehen der ADMINISTRATOR-Berechtigung zurückgenommen werden. Wenn Sie also einem Benutzer die ADMINISTRATOR-Berechtigung gewähren und dann diesem Benutzer die CREATE-Berechtigung entziehen, verfügt er dennoch weiterhin über die CREATE-Berechtigung. Bei der Angabe des Objekts können Sie das optionale Schlüsselwort TABLE zum Gewähren von Zugriffsrechten auf Tabellen oder Ansichten verwenden. In diesem Kontext wird das Schlüsselwort VIEW nicht verwendet. Sie können Zugriffsrechte auf eine Methode auch unter Verwendung des erforderlichen Schlüsselworts METHOD entziehen. Es ist möglich, folgende Datenbankberechtigungen zu gewähren: 10 Berechtigung Beschreibung ADMINISTRATOR Gewährt die Berechtigungen startup, write, create, drop, rename, create role und create schema STARTUP Benutzer dürfen die Datenbank starten WRITE Benutzer dürfen in die Datenbank schreiben CREATE Benutzer dürfen Tabellen erstellen DROP Benutzer dürfen Tabellen entfernen RENAME Benutzer dürfen Tabellen umbenennen CREATE ROLE Benutzer dürfen Rollen erstellen CREATE SCHEMA Benutzer dürfen Schemas erstellen CREATE ROLE und CREATE SCHEMA werden standardmäßig gewährt, wenn ein Benutzer erstellt wird. Syntax <grant statement> ::= <grant database privileges statement> | <grant object privileges statement> | <grant role statement> <grant database privileges statement> ::= 114 10 Blackfish SQL GRANT <database privilege commalist> TO <grantee commalist> [ WITH ADMIN OPTION ] <grant object privileges statement> ::= GRANT < object privileges> ON <privilege object> TO <grantee commalist> [ WITH GRANT OPTION ] [ GRANTED BY <grantor> ] <grant role statement> ::= GRANT <role name commalist> TO <grantee commalist> [ WITH ADMIN OPTION ] [ GRANTED BY <grantor> ] <database privilege> ::= STARTUP | ADMINISTRATOR | WRITE | CREATE | DROP | RENAME | CREATE ROLE | CREATE SCHEMA <grantee> ::= PUBLIC | <user name> | <role name> <object privileges> ::= ALL PRIVILEGES | <privilege commalist> <privilege>::= SELECT | INSERT [ ( <column name commalist> ) ] | UPDATE [ ( <column name commalist> ) ] | REFERENCES [ ( <column name commalist> ) ] | DELETE | EXECUTE <privilege object> ::= [TABLE] <table name or view name> | METHOD <method name> <grantor> ::= CURRENT_USER | CURRENT_ROLE 10 Beispiele Im folgenden Beispiel erhält USER_1 SELECT- und INSERT-Berechtigungen für Tabelle T1. USER_2 erhält die SELECT-Berechtigung für Tabelle T1, weil die SELECT-Berechtigung ROLE_B gewährt und ROLE_B zu USER_2 zugewiesen wurde. USER_2 kann die SELECT-Berechtigung aber erst verwenden, nachdem ROLE_B mit einer SET ROLE-Anweisung aktiviert wurde. GRANT SELECT ON TABLE T1 TO USER_1, ROLE_B; GRANT INSERT ON T1 TO USER_1; GRANT ROLE_B TO USER_2; 115 Blackfish SQL 10 REVOKE Mit der REVOKE-Anweisung können folgende Vorgänge ausgeführt werden: • Sie entzieht PUBLIC, Benutzern oder Rollen Objektberechtigungen wie beispielsweise INSERT oder SELECT auf Tabellen oder Methoden. • Wenn der Benutzer oder die Rolle die gerade entzogene Berechtigung anderen Benutzern gewährt hat, entzieht CASCADE diesen anderen Benutzern ebenfalls die Berechtigung. Wenn Ansichten von der entzogenen Berechtigung abhängen, werden sie entfernt. • Wenn die REVOKE-Anweisung RESTRICT enthält, schlägt die Anweisung fehl, wenn der Berechtigte die erworbenen Berechtigungen anderen Benutzern oder Rollen gewährt hat. • Sie entzieht Benutzern oder Rollen Datenbankberechtigungen wie beispielsweise STARTUP oder RENAME. • Sie entzieht die Rollen Benutzern oder anderen Rollen. • Sie entzieht einer Rolle die ADMIN-Option, ohne die Rolle selbst zu entziehen. • REVOKE GRANT OPTION FOR Berechtigung entzieht das Recht zum Gewähren der Berechtigung, ohne die Berechtigung selbst zu entziehen. REVOKE ADMIN OPTION FOR Rolle entzieht das Recht zum Gewähren der benannten Rolle, ohne die Rolle selbst zu entziehen. Bei der Angabe des Objekts können Sie das optionale Schlüsselwort TABLE zum Entziehen von Zugriffsrechten auf Tabellen oder Ansichten verwenden. In diesem Kontext wird das Schlüsselwort VIEW nicht verwendet. Sie können Zugriffsrechte auf eine Methode auch unter Verwendung des erforderlichen Schlüsselworts METHOD entziehen. Syntax <revoke statement> ::= <revoke database privileges statement> | <revoke object privileges statement> | <revoke role statement> <revoke database privileges statement> ::= REVOKE <database privilege commalist> FROM <grantee commalist> <revoke object privileges statement> ::= REVOKE [ GRANT OPTION FOR ] < object privileges> ON <privilege object> FROM <grantee commalist> [ GRANTED BY <grantor> ] [ CASCADE|RESTRICT ] 10 <revoke role statement> ::= REVOKE [ ADMIN OPTION FOR ] <role name commalist> FROM <grantee commalist> [ GRANTED BY <grantor> ] [ CASCADE|RESTRICT ] <database privilege> ::= STARTUP | ADMINISTRATOR | WRITE | CREATE | DROP | RENAME | CREATE ROLE | CREATE SCHEMA <grantee> ::= PUBLIC | <user name> | <role name> <object privileges> ::= 116 10 Blackfish SQL ALL PRIVILEGES | <privilege commalist> <privilege>::= SELECT | INSERT [ ( <column name commalist> ) ] | UPDATE [ ( <column name commalist> ) ] | REFERENCES [ ( <column name commalist> ) ] | DELETE | EXECUTE <privilege object> ::= [TABLE] <table name or view name> | METHOD <method name> <grantor> ::= CURRENT_USER | CURRENT_ROLE Beispiel 1 In allen folgenden Beispielen ist der Name vor dem Doppelpunkt der Name des Benutzers, der die Anweisung ausführt. Die folgenden GRANT-Anweisungen werden von den Benutzern U1, U2 und U3 ausgeführt und bilden den Kontext für die nachfolgenden Beispiele: Anweisung 1: U1: GRANT SELECT ON TABLE T1 TO U2 WITH GRANT OPTION; Anweisung 2: U2: GRANT SELECT ON TABLE T1 TO U3 WITH GRANT OPTION; Anweisung 3: U3: GRANT SELECT ON TABLE T1 TO U4 WITH GRANT OPTION; Beispiel 1a: Die RESTRICT-Option sorgt dafür, dass folgende REVOKE-Anweisung fehlschlägt, weil Benutzer U2 die Berechtigung, die ihm in Anweisung 1 gewährt wurde, in Anweisung 2 weitergegeben hat. U1: REVOKE SELECT ON TABLE T1 FROM U2 RESTRICT; Beispiel 1b: Das folgende Beispiel wird erfolgreich ausgeführt und die in den Anweisungen 1, 2 und 3 gewährten Berechtigungen werden entzogen. U1: REVOKE SELECT ON TABLE T1 FROM U2 CASCADE; Beispiel 1c: 10 Die RESTRICT-Option sorgt dafür, dass folgende Anweisung fehlschlägt, weil Benutzer U2 die GRANT OPTION, die ihm in Anweisung 1 gewährt wurde, in Anweisung 2 weitergegeben hat. U1: REVOKE GRANT OPTION FOR SELECT ON TABLE T1 FROM U2 RESTRICT; Beispiel 1d: Das folgende Beispiel wird erfolgreich ausgeführt und die in den Anweisungen 2 und 3 gewährten Berechtigungen werden entzogen. U2 behält die SELECT-Berechtigung für T1, kann diese Berechtigung aber nicht an andere Benutzer weitergeben. U1: REVOKE GRANT OPTION FOR SELECT ON TABLE T1 FROM U2 CASCADE; Beispiel 2 Die folgenden GRANT- und CREATE-Anweisungen werden von den Benutzern U1, U2 und U3 ausgeführt und bilden den Kontext für die nachfolgenden Beispiele. Der Name vor dem Doppelpunkt ist der Name des Benutzers, der die Anweisung ausführt. 117 Blackfish SQL 10 Anweisung 1: U1: GRANT SELECT ON TABLE T1 TO U2 WITH GRANT OPTION; Anweisung 2: U2: GRANT SELECT ON TABLE T1 TO U3 WITH GRANT OPTION; Anweisung 3: U3: GRANT SELECT ON TABLE T1 TO U4 WITH GRANT OPTION; Anweisung 4: U2: CREATE VIEW V2 AS SELECT A, B FROM T1; Anweisung 5: U3: CREATE VIEW V3 AS SELECT A, B FROM T1; Beispiel 2a: Das folgende Beispiel wird erfolgreich ausgeführt und die in den Anweisungen 1, 2 und 3 gewährten Berechtigungen werden entzogen. Zusätzlich werden die Ansichten V2 und V3 entfernt, weil U2 und U3 nicht mehr über die SELECT-Berechtigung für T1 verfügen, die für die Ansichten erforderlich ist. U1: REVOKE SELECT ON TABLE T1 FROM U2 CASCADE Beispiel 2b: Das folgende Beispiel wird erfolgreich ausgeführt und die in den Anweisungen 2 und 3 gewährten Berechtigungen werden entzogen. Der Benutzer U2 behält die SELECT-Berechtigung für T1, kann diese Berechtigung aber nicht an andere Benutzer weitergeben. Zusätzlich wird die Ansicht V3 entfernt, weil U3 nicht mehr über die SELECT-Berechtigung für T1 verfügt. Die Ansicht V2 wird nicht entfernt, weil U2 weiterhin über die SELECT-Berechtigung für T1 verfügt. U1: REVOKE GRANT OPTION FOR SELECT ON TABLE T1 FROM U2 CASCADE Beispiel 3 Die folgenden GRANT- und CREATE-Anweisungen werden von den Benutzern U1, U2 und U3 ausgeführt und bilden den Kontext für die nachfolgenden Beispiele. Der Name vor dem Doppelpunkt ist der Name des Benutzers, der die Anweisung ausführt. Anweisung 1: U1: CREATE ROLE R1; Anweisung 2: U1: GRANT SELECT ON TABLE T1 TO R1; Anweisung 3: 10 U1: GRANT R1 TO U2 WITH ADMIN OPTION; Anweisung 4: U2: GRANT R1 TO U3 WITH ADMIN OPTION; Anweisung 5: U3: GRANT R1 TO U4 WITH ADMIN OPTION; Beispiel 3a: Die folgende Anweisung schlägt fehl, weil Benutzer U2 die durch die Zuweisung der Rolle R1 erworbenen Berechtigungen anderen Benutzern oder Rollen gewährt hat. U1: REVOKE R1 FROM U2 RESTRICT; Beispiel 3b: 118 10 Blackfish SQL Die folgende Anweisung wird erfolgreich ausgeführt. Die in den Anweisungen 3, 4 und 5 gewährten Berechtigungen werden entzogen. U1: REVOKE R1 FROM U2 CASCADE; Beispiel 3c: Die folgende Anweisung schlägt fehl, weil Benutzer U2 die in Anweisung 3 erworbene Berechtigung ADMIN OPTION weitergegeben hat. U1: REVOKE ADMIN OPTION FOR R1 FROM U2 RESTRICT; Beispiel 3d: Die folgende Anweisung wird erfolgreich ausgeführt. Die in den Anweisungen 4 und 5 gewährten Berechtigungen werden entzogen. Benutzer U2 behält die durch Rolle R1 gewährten Berechtigungen, kann diese Rolle aber anderen Benutzern nicht gewähren. U1: REVOKE ADMIN OPTION FOR R1 FROM U2 CASCADE; Escape-Syntax Blackfish SQL unterstützt Escape-Sequenzen für folgende Elemente: • Datums- und Zeitliterale • OUTER JOIN • Escape-Zeichen einer LIKE-Klausel • Aufrufe gespeicherter Prozeduren Escape-Sequenzen werden immer in geschweiften Klammern "{}" angegeben. Sie werden verwendet, um die Funktionalität von SQL zu erweitern. Datums- und Zeitliterale {T 'hh:mm:ss'} Gibt eine Zeit an, die in der folgenden Reihenfolge eingegeben werden muss: Stunden, Minuten, Sekunden. {D 'yyyy-mm-dd} Gibt ein Datum an, das in der folgenden Reihenfolge eingegeben werden muss: Jahr, Monat, Tag. {TS 'yyyy-mm-dd hh:mm:ss'} Gibt ein Systemdatum und eine Systemzeit ("Timestamp") an, die in der vorgegebenen Form eingegeben werden müssen: Jahr, Monat, Tag, Stunde, Minute, Sekunde. Beispiele INSERT SELECT SELECT SELECT 10 INTO tablename VALUES({D '2004-2-3'}, {T '2:55:11'}); {T '10:24'} FROM tablename; {D '2000-02-01'} FROM tablename; {TS '2000-02-01 10:24:32'} FROM tablename; OUTER JOINs {OJ <join_table_expression>} Ein Outer Join wird auf den angegebenen Tabellenausdruck angewandt. Beispiel SELECT * FROM {OJ a LEFT JOIN b USING(id)}; 119 Blackfish SQL 10 Escape-Zeichen für LIKE {ESCAPE <char>} Das angegebene Zeichen wird zum Escape-Zeichen für die vorhergehende LIKE-Klausel. Beispiel SELECT * FROM a WHERE name LIKE '%*%' {ESCAPE '*'} Aufrufe gespeicherter Prozeduren {call <procedure_name> (<argument_list>)} Oder wenn die Prozedur einen Ergebnisparameter zurückgibt: {? = call <procedure_name> (<argument_list>)} Beispiel 1 Die Methode, die IncreaseSalaries implementiert, aktualisiert die Tabelle salaries mit einem prozentualen Zuwachs für alle Mitarbeiter. Ein Verbindungsobjekt wird implizit an die Methode übergeben. Von Statement.executeUpdate wird ein updateCount aller Zeilen zurückgegeben, die von IncreaseSalaries betroffen sind. {CALL IncreaseSalaries(10)}; Beispiel 2 Die Parametermarkierung gibt die Position der Ausgabeparameter an, aus denen das Abfrageergebnis der gespeicherten Prozedur abgerufen werden kann. {?=CALL ABS(-765)}; Escape-Funktionen Funktionen werden in folgendem Format geschrieben, wobei FN bedeutet, dass die nachfolgende Funktion ausgeführt werden soll: {fn <function_name>(<argument_list>) } Numerische Funktionen 10 Funktionsname Funktion gibt zurück ABS(number) Absoluter Wert von number ACOS(float) Arcuscosinus von float im Bogenmaß ASIN(float) Arcussinus von float im Bogenmaß ATAN(float) Arcustangens von float im Bogenmaß ATAN2(float1, float2) Arcustangens von float2 im Bogenmaß dividiert durch float1 CEILING(number) Kleinste Ganzzahl >= number COS(float) Cosinus von float im Bogenmaß COT(float) Cotangens von float im Bogenmaß DEGREES(number) Grad von number (Bogenmaß) 120 10 Blackfish SQL EXP(float) Exponentialfunktion von float FLOOR(number) Größte Ganzzahl <= number LOG(float) Logarithmus zur Basis e von float LOG10(float) Logarithmus zur Basis 10 von float MOD(integer1, integer2) Rest von integer1 dividiert durch integer2 PI() Die Konstante pi POWER(number, power) number potenziert mit power (Ganzzahl) RADIANS(number) Bogenmaß von number (Grad) RAND(integer) Zufallszahl als Fließkommawert auf Basis eines Startwerts (integer) ROUND(number, places) number gerundet auf n (places) Stellen SIGN(number) -1 bedeutet: Zahl (number) ist < 0; 0 bedeutet: Zahl (number) = 0; 1 bedeutet: Zahl (number) ist > 0 SIN(float) Sinus von float im Bogenmaß SQRT(float) Quadratwurzel von float TAN(float) Tangens von float im Bogenmaß TRUNCATE(number, places) number gekürzt auf n (places) Stellen String-Funktionen Funktionsname Funktion gibt zurück ASCII(string) Ganzzahl, die für den ASCII-Wert des Zeichens in string steht, das sich am weitesten links befindet. CHAR(code) Zeichen mit dem ASCII-Wert code, wobei code zwischen 0 und 255 sein muss CONCAT(string1, string2) Zeichen-String, der erzeugt wird durch Anhängen von string2 an string1; ist ein String NULL, hängt das Ergebnis vom DBMS ab DIFFERENCE(string1, Ganzzahl, die den Unterschied zwischen den von der Funktion SOUNDEX für string1 und string2 string2) zurückgegebenen Werten angibt INSERT(string1, start, Ein Zeichen-String, der gebildet wird durch Löschen von length Zeichen aus string1 beginnend bei length, string2) start und durch Einfügen von string2 in string1 bei start. LCASE(string) Konvertiert alle Großbuchstaben in string in Kleinbuchstaben LEFT(string, count) Die n (count) Zeichen in string, die sich am weitesten links befinden LENGTH(string) Anzahl der Zeichen in string, ausgenommen nachgestellter Leerzeichen LOCATE(string1, string2[, start]) Position des ersten Vorkommens von string1 in string2. Die Suche beginnt am Anfang von string2; wenn start angegeben ist, beginnt die Suche bei start. Gibt 0 zurück, wenn string1 nicht in string2 enthalten ist. Position 1 ist das erste Zeichen in string2. LTRIM(string) Alle Zeichen von string, wobei die führenden Leerzeichen entfernt wurden 10 REPEAT(string, count) Ein Zeichen-String, der durch stringcount-faches Wiederholen geformt wird. REPLACE(string1, string2, string3) Ersetzt alle Vorkommen von string2 in string1 durch string3 RIGHT(string, count) Die n (count) Zeichen in string, die sich am weitesten rechts befinden RTRIM(string) Alle Zeichen von string, ausgenommen der nachfolgenden Leerzeichen 121 Blackfish SQL 10 SOUNDEX(string) Ein datenquellenabhängiger Zeichen-String, der den Klang von Wörtern repräsentiert; dies kann beispielsweise ein vierstelliger SOUNDEX-Code oder eine phonetische Darstellung der Wörter sein. SPACE(count) Ein Zeichen-String, der aus n (count) Leerzeichen besteht. SUBSTRING(string, start, length) Ein Zeichen-String, der aus n (length) Zeichen aus string beginnend bei start besteht. UCASE(string) Konvertiert alle Kleinbuchstaben in string in Großbuchstaben Beispiele SELECT {FN LCASE('Hello')} FROM tablename; SELECT {FN UCASE('Hello')} FROM tablename; SELECT {FN LOCATE('xx', '1xx2')} FROM tablename; SELECT {FN LTRIM('Hello')} FROM tablename; SELECT {FN RTRIM('Hello')} FROM tablename; SELECT {FN SUBSTRING('Hello', 3, 2)} FROM tablename; SELECT {FN CONCAT('Hello ', 'there.')} FROM tablename; Datums- und Zeitfunktionen 10 Funktionsname Funktion gibt zurück CURDATE() Das aktuelle Datum als Datumswert CURTIME() Die aktuelle lokale Zeit als Zeitwert DAYNAME(date) Ein Zeichen-String für die Tag-Komponente des Datums; der Name des Tages hängt von der Datenquelle ab DAYOFMONTH(date) Eine Ganzzahl von 1 bis 31 für den Monatstag, der aus date ermittelt wird DAYOFWEEK(date) Eine Ganzzahl von 1 bis 7 für den Wochentag in date; Sonntag = 1 DAYOFYEAR(date) Eine Ganzzahl von 1 bis 366 für den Tag des Jahres in date HOUR(time) Eine Ganzzahl von 0 bis 23 für die Stundenzahl der Uhrzeit in time MINUTE(time) Eine Ganzzahl von 0 bis 59 für die Minutenzahl der Uhrzeit in time MONTH(date) Eine Ganzzahl von 1 bis 12 für den Monat, der aus date ermittelt wird MONTHNAME(date) Ein Zeichen-String für den Monat in date; der Monatsname hängt von der Datenquelle ab NOW() Ein Timestamp-Wert mit dem aktuellen Datum und der aktuellen Uhrzeit QUARTER(date) Eine Ganzzahl von 1 bis 4 für das Quartal in date; 1.Januar bis 31.März = 1 SECOND(time) Eine Ganzzahl von 0 bis 59 für die Sekundenzahl der Uhrzeit in time TIMESTAMPADD(interval, count, timestamp) Ein Zeitstempel, der berechnet wird durch Hinzufügen von n (count) Intervallen (interval) zu timestamp; interval kann einer der folgenden Werte sein: SQL_TSI_FRAC_SECOND, SQL_TSI_SECOND, SQL_TSI_MINUTE, SQL_TSI_HOUR, SQL_TSI_DAY, SQL_TSI_WEEK, SQL_TSI_MONTH, SQL_TSI_QUARTER oder SQL_TSI_YEAR 122 10 Blackfish SQL TIMESTAMPDIFF(interval, Eine Ganzzahl, die die Anzahl der Intervalle (interval) angibt, um die timestamp2 größer ist als timestamp1, timestamp2) timestamp1; interval kann eines der folgenden Optionen sein: SQL_TSI_FRAC_SECOND, SQL_TSI_SECOND, SQL_TSI_MINUTE, SQL_TSI_HOUR, SQL_TSI_DAY, SQL_TSI_WEEK, SQL_TSI_MONTH, SQL_TSI_QUARTER oder SQL_TSI_YEAR WEEK(date) Eine Ganzzahl von 1 bis 53 für die Woche des Jahres in date YEAR(date) Eine Ganzzahl, die die Jahreszahl in date repräsentiert Beispiele SELECT {FN NOW()} FROM tablename; SELECT {FN CURDATE() } FROM tablename; SELECT {FN CURTIME() } FROM tablename; SELECT {FN DAYOFMONTH(datecol) } FROM tablename; SELECT {FN YEAR(datecol)} FROM tablename; SELECT {FN MONTH(datecol)} FROM tablename; SELECT {FN HOUR(timecol) } FROM tablename; SELECT {FN MINUTE(timecol) } FROM tablename; SELECT {FN SECOND(timecol) } FROM tablename; Systemfunktionen Funktionsname Funktion gibt zurück DATABASE() Name der Datenbank IFNULL(expression, value) value, wenn expression NULL ist; expression, wenn expression nicht NULL ist USER() Der Benutzername für das DBMS Konvertierungsfunktionen 10 Funktionsname Funktion gibt zurück CONVERT(value, value wird in SQLtype konvertiert, wobei SQLtype einer der folgenden SQL-Typen sein kann: BIGINT, SQLtype) BINARY, BIT, CHAR, DATE, DECIMAL, DOUBLE, FLOAT, INTEGER, LONGVARBINARY, LONGVARCHAR, REAL, SMALLINT, TIME, TIMESTAMP, TINYINT, VARBINARY oder VARCHAR Beispiel SELECT {FN CONVERT('34.5',DECIMAL(4,2))} FROM tablename; ISQL ISQL ist ein SQL-Befehlsinterpreter, mit dem SQL-Anweisungen interaktiv ausgeführt werden können. Diese Funktion ist nur bei Blackfish SQL für Java verfügbar. 123 Blackfish SQL 10 Hilfe aufrufen Um Hilfe für Blackfish SQL System-Eingabeaufforderung: ISQL anzuzeigen, führen Sie einen der folgenden Hilfebefehle aus: Von der • isql -? zeigt die ISQL-Startoptionen an. • isql -help zeigt die ISQL-Optionen an. Von der SQL-Eingabeaufforderung: • HELP CREATE zeigt Hilfe zum Erstellen von Datenquellen an. HELP SHOW zeigt eine Liste der SHOW-Befehle mit kurzen Beschreibungen an. • HELP SET zeigt eine Liste von SET-Befehlen mit einer kurzen Beschreibung für jeden Befehl an. ISQL starten Um Blackfish SQL ISQL zu starten, stellen Sie entweder sicher, dass sich BlackfishSQL_install_dir\bin in Ihrem Systempfad befindet, oder wechseln Sie zu diesem Verzeichnis, um den ISQL-Befehl auszuführen. Folgende Optionen stehen zur Verfügung: Startoptionen für ISQL Option mit Argumenten Beschreibung -user userName Gibt den Benutzernamen für diese Verbindung an. -password password Gibt das mit dem Benutzernamen (userName) verbundene Passwort an. -role roleName Aktiviert die benannte Rolle für den Benutzer. -input filename Führt alle Befehle in der angegebenen Datei aus und beendet ISQL. -output filename Leitet die gesamte Ausgabe in die benannte Datei um. -datasource filename Gibt eine alternative Datenquelldatei an -echo Gibt alle Befehle aus, bevor sie ausgeführt werden. -stacktrace Gibt einen Stacktrace für jeden entdeckten Fehler aus. -pagelength length Gibt alle n (length) Zeilen Spaltentitel aus. -x Gibt alle Datendefinitionsanweisungen der aktuellen Verbindung aus und beendet ISQL. -z Zeigt die Versionsinformation an und beendet ISQL. 10 Datenquellen- und Dateiverwaltung Wenn Sie ISQL gestartet haben, sind folgende Befehle zur Verwaltung der Datenquellverbindungen, zur Datei- und Sitzungsverwaltung verfügbar. Sie können während einer ISQL-Sitzung wie folgt eine Liste dieser Befehle abrufen: SHOW CREATE; Es gibt zwei zusätzliche Gruppen von Befehlen, die später in diesem Abschnitt näher erläutert werden: SHOW-Befehle und SET-Befehle. Die SQL-Befehle, die für die Datendefinition, Datenmanipulation, Sicherheit und das Transaktionsmanagement verfügbar sind, werden in diesem Kapitel beschrieben. ISQL-Befehle zur Datenquellen- und Dateiverwaltung 124 10 Blackfish SQL Befehl Beschreibung CREATE Verbindet eine Datenquelle mit dem dataSourceName. Sie übergeben diesen dataSourceName an DATASOURCE CONNECT, um eine Verbindung zu einer Datenbank herzustellen. Weitere Informationen über das dataSourceName Erstellen von Datenquellen in ISQL finden Sie nachfolgend unter "Datenquellen mit ISQL erstellen". [dataSourceClassName] properties CONNECT dataSourceName [userpassword] Stellt eine Verbindung zur Datenquelle (dataSourceName) her. Bevor Sie CONNECT verwenden können, müssen Sie CREATE DATASOURCE ausführen, um eine Datenbank mit dem dataSourceName, den Sie an CONNECT übergeben, zu verbinden. Sie müssen den Benutzernamen und das Passwort nicht angeben, wenn diese bereits als Teil der CREATE DATASOURCE-Anweisung angegeben wurden. INPUT filename Verwendet den Inhalt der benannten SQL-Datei als Input. OUTPUT filename Schreibt die Ausgabe in die angegebene Datei. OUTPUT Schreibt die Ausgabe in stdout. EXPORT Exportiert die Datendefinitionsanweisungen und die Daten der aktuellen Datenbank in SQL. EXPORT [userpassword] Exportiert die Datendefinitionsanweisungen und die Daten der aktuellen Datenbank in die angegebene Datenquelle. Um eine Datei zu exportieren, verwenden Sie EXPORT in Verbindung mit OUTPUT: OUTPUT sqlfile.txt; EXPORT; IMPORT [userpassword] Importiert die Datendefinitionsanweisungen und die Daten aus der angegebenen Datenquelle. VERSION Zeigt die ISQL-Version und die jeweilige Version der verbundenen Datenbanken an. EXIT Schreibt Änderungen fest (Commit) und beendet ISQL. QUIT Macht Änderungen rückgängig (Rollback) und beendet ISQL. Datenquellen mit ISQL erstellen In diesem Abschnitt erfahren Sie mehr über das Erstellen von Datenquellen in ISQL mit dem Befehl CREATE DATASOURCE. Die Syntax von CREATE DATASOURCE lautet: CREATE DATASOURCE dataSourceName [dataSourceClassName] properties Die Argumente für den CREATE DATASOURCE-Befehl lauten: dataSourceName identifiziert die neue Datenquelle und kann ein beliebiger SQL-Bezeichner sein. dataSourceClassName ist die Java-Klasse, die die Eigenschaften bereitstellt, die zur Verbindungsaufnahme mit einer JDBC-Datenbank erforderlich sind. Sie muss eine Implementierung des Standard-JDBC-Interface javax.sql.DataSource sein. Wird dieses Argument nicht angegeben, wird com.borland.javax.sql.JdbcDataSource verwendet. Zum Zugriff auf InterBase-Datenbanken können Sie interbase.interclient.DataSource verwenden. properties können alle Eigenschaften sein, die von der unter dataSourceClassName angegebenen Klasse bereitgestellt werden. Eigenschaften werden durch Kommas getrennt und enthalten für gewöhnlich Folgendes: • user='username' Wenn Sie hier keinen Benutzernamen angeben, können Sie ihn als Teil der CONNECT-Anweisung bereitstellen. • password='password' Wenn Sie hier keinen Benutzernamen angeben, können Sie ihn als Teil der CONNECT-Anweisung bereitstellen. • databaseName='database_name_to_connect_to' Beispiel Sie können für alle Eigenschaften der Datenquellklasse Werte angeben. Um beispielsweise eine neue Datenbank zu erstellen, fügen Sie Folgendes ein: 125 10 Blackfish SQL 10 CREATE=true: CREATE DATASOURCE JDS user=SYSDBA, password=masterkey, databaseName='c:/databases/test.jds',CREATE=true'; Beispiele In den nachfolgenden beiden Beispielen wird die Blackfish com.borland.javax.sql.JdbcDataSource verwendet, da kein className angegeben wird. SQL-Standardklasse Im nachfolgenden Beispiel wird eine lokale Datenquelle (JDS_LOCAL) erstellt: CREATE DATASOURCE JDS_LOCAL user=SYSDBA, password=masterkey, create=true, databaseName='c:/test.jds'; Im nächsten Beispiel wird eine Remote-Datenquelle (JDS_REMOTE) erstellt. Zudem wird die Datenbank "test.jds" erstellt. CREATE DATASOURCE JDS_REMOTE user=SYSDBA, password=masterkey, networkProtocol=tcp, serverName=localhost, portNumber=2508, create=true, databaseName='c:/test.jds'; ISQL SHOW-Befehle 10 Befehl Beschreibung SHOW DATASOURCE [name] Zeigt alle Datenquellen bzw. die angegebene Datenquelle an. SHOW DATABASE Zeigt die Einstellungen für die aktuelle Datenbank an. SHOW VERSION Zeigt die ISQL-Version und die jeweilige Version aller verbundenen Datenbanken an. SHOW DDL Zeigt die Datendefinitionsanweisungen für die aktuelle Datenbank an. SHOW SYSTEM Zeigt die Systemtabellen an. SHOW TABLE [[schema.]table] Zeigt alle Tabellen bzw. die angegebene Tabelle an. SHOW VIEW [[schema.]view] Zeigt alle Ansichten bzw. die angegebene Ansicht an. SHOW [[schema.]name] PROCEDURE Zeigt alle Prozeduren bzw. die angegebene Prozedur an. SHOW [[schema.]name] SHOW INDEX [schema.]table]] FUNCTION Zeigt alle Funktionen bzw. die angegebene Funktion an. [index [ON Zeigt alle Indizes bzw. den angegebenen Index an. SHOW ROLES Listet alle in der Datenbank definierten Rollen auf. SHOW USERS Listet alle in der Datenbank definierten Benutzer auf. SHOW GRANT [[schema.]table] SHOW GRANT [[schema.]view] 126 TABLE Listet alle Zugriffsrechte auf Tabellen auf, denen WITH GRANT OPTION gewährt wurde. VIEW Listet alle Zugriffsrechte auf Ansichten auf, denen WITH GRANT OPTION gewährt wurde. 10 Blackfish SQL SHOW GRANT PROCEDURE Listet alle Zugriffsrechte auf Prozeduren auf, denen WITH GRANT OPTION gewährt wurde. [[schema.]name] SHOW GRANT [[schema.]name] FUNCTION Listet alle Zugriffsrechte auf Funktionen auf, denen WITH GRANT OPTION gewährt wurde. SHOW GRANT ROLE [role] SHOW GRANT [user|role] Listet alle Benutzer auf, denen die angegebene Rolle gewährt wurde. DATABASE Listet alle Datenbankberechtigungen auf, die dem angegebenen Benutzer oder der angegebenen Rolle gewährt wurden. ISQL SET-Befehle Befehl Beschreibung SET Zeigt den aktuellen Wert von ECHO, STACKTRACE und PAGELENGTH an. SET {ON|OFF} ECHO Schaltet die Ausgabe (echo) aller Befehle an die Standardausgabe ein bzw. aus. SET STACKTRACE Schaltet die Anzeige von Fehler-Traces ein bzw. aus. {ON|OFF} SET PAGELENGTH Legt die Seitenlänge in Zeilen fest. Die Vorgabe ist 0, d . h. die Spaltenüberschriften werden nur einmal number ausgegeben. Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( see page 57) see page 61) Blackfish SQL-Anwendungen optimieren ( 10 see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( see page 43) see page 137) see page 141) 127 11 Blackfish SQL 11 Blackfish SQL-Anwendungen optimieren In diesem Abschnitt werden Möglichkeiten beschrieben, um das Verhalten, die Zuverlässigkeit und die Größe von Blackfish SQL-Anwendungen zu optimieren. Sofern nicht anderweitig vermerkt, bezieht sich DataStoreConnection auf ein Objekt des Typs DataStoreConnection oder DataStore, das zum Öffnen einer Verbindung zu einer Blackfish SQL-Datenbankdatei verwendet wird. • Datenbanken schnell laden • Allgemeine Empfehlungen • Transaktionale Anwendungen optimieren • Zum Einsatz bereitgestellte Ressourcen für Blackfish SQL für Java-Anwendungen ausdünnen • AutoIncrement-Spalten • Blackfish SQL Companion-Komponenten • Datenmodule für DataExpress-Komponenten verwenden Datenbanken schnell laden Im Folgenden finden Sie einige Tipps, wie Sie die Leistungsfähigkeit von Anwendungen beim Laden von Datenbanken verbessern können: • Verwenden Sie so oft wie möglich Prepared-Anweisungen oder Befehle. Wenn sich die Anzahl der Parameter von einer Einfügung zur nächsten ändert, löschen Sie die Parameter, bevor Sie die neuen Parameter festlegen. • Erstellen Sie die Tabelle ohne Primärschlüssel, Fremdschlüssel oder sekundäre Indizes. Laden Sie die Tabelle und erstellen Sie anschließend alle erforderlichen Primärschlüssel, Fremdschlüssel oder sekundäre Indizes. Optimierung von Ladevorgängen für Java-spezifische Datenbanken Verwenden Sie die DataExpress-Klasse TextDataFile zum Importieren von Textdateien. Sie verfügt über einen schnellen Parser und kann Daten schnell laden. Sie müssen den TableDataSet-Store auf eine DataStoreConnection setzen und die Eigenschaft StoreName auf den Namen Ihrer Tabelle in der Blackfish SQL-Datenbank. Wenn Sie eine neue Datenbank laden: 1. Erstellen Sie zuerst die Datenbank als nichttransaktional. 129 11 Blackfish SQL 11 2. Laden Sie die nicht transaktionale Datenbank mithilfe der DataExpress-Komponenten StorageDataSet.addRow oder TextDataFile. 3. Wenn der Ladevorgang abgeschlossen ist, machen Sie die Datenbank mithilfe der Eigenschaft DataStore.TxManager transaktional. Dadurch wird die Datenbank zwei- bis dreimal schneller. Allgemeine Empfehlungen Dieser Abschnitt führt einige allgemeine Richtlinien zur Verbesserung der Leistung von Blackfish SQL-Anwendungen auf. Datenbanken ordnungsgemäß schließen Wenn eine Datenbank nicht ordnungsgemäß geschlossen wurde, verursacht sie beim nächsten Öffnen durch einen Prozess eine Verzögerung. Der Grund dafür ist, dass Blackfish SQL etwa 8-10 Sekunden benötigt, um sicherzustellen, das kein anderer Prozess die Datenbank geöffnet hat. Um zu gewährleisten, dass eine Datenbank ordnungsgemäß geschlossen wird, stellen Sie sicher, dass alle Verbindungen geschlossen sind, wenn sie nicht mehr benötigt werden. Falls es schwierig ist sicherzustellen, dass alle Verbindungen geschlossen sind, kann eine Verbindung mit Administratorrechten die integrierte gespeicherte Prozedur DB_ADMIN.CLOSE_OTHER_CONNECTIONS aufrufen, um sicherzustellen, dass alle anderen Verbindungen geschlossen werden. Das Schließen der Verbindungen bietet darüber hinaus den Vorteil, dass danach der für den Blackfish SQL-Cache reservierte Speicher freigegeben wird. Derzeit kann auf nichttransaktionale Datenbanken nur dann per SQL zugegriffen werden, wenn die Nur-Lese-Eigenschaft der Datenbank den Wert "true" hat. DataExpress-Java Beans können jedoch Schreiboperationen in einer nichttransaktionalen Datenbank durchführen. Das Schließen einer nichttransaktionalen Blackfish SQL-Datenbank stellt sicher, dass alle Änderungen auf die Festplatte gespeichert werden. Für alle geöffneten Instanzen von DataStoreConnection wird ein Daemon-Thread ausgeführt, der geänderte Cache-Daten fortwährend auf der Festplatte speichert. (Standardmäßig werden geänderte Daten alle 500 Millisekunden gespeichert.) Wenn Sie die Java VM direkt beenden, ohne die Datenbank zu schließen, kann der Daemon-Thread unter Umständen den letzten Satz geänderter Daten nicht mehr speichern. Es besteht eine geringe Wahrscheinlichkeit, dass dabei eine nicht transaktionale Blackfish SQL beschädigt wird. Eine transaktionale Blackfish SQL-Datenbank verliert garantiert keine Daten, allerdings macht der Transaktions-Manager unbestätigte Änderungen rückgängig. Java-spezifische Datenbank schließen Wenn in Ihrer Anwendung DataExpress-JavaBean-Komponenten verwendet werden, schließen Sie alle StorageDataSets, deren store-Eigenschaft auf DataStoreConnection gesetzt ist, wenn Sie sie nicht mehr benötigen. Damit werden Blackfish SQL-Ressourcen freigemacht, die mit dem StorageDataSet verknüpft sind, und die Möglichkeit geschaffen, eine Speicherbereinigung des StorageDataSet durchzuführen. Sie können die Methode DataStore.shutdown() verwenden, um sicherzustellen, dass alle Datenbankverbindungen beendet werden, bevor eine Anwendung geschlossen wird. 11 Den Festplatten-Cache für Blackfish SQL optimieren Die vorgegebene Maximalgröße des Cache-Speichers für Blackfish SQL-Datenbanken beträgt 512 Cache-Blöcke. Die vorgegebene Blockgröße ist 4.096 Byte. Daher erreicht der Cache-Speicher seine maximale Kapazität bei etwa 512 x 4.096 Byte (2 MB). Dieser Speicher wird nach Bedarf zugewiesen. In seltenen Fällen kann es vorkommen, dass alle Blöcke verwendet werden und der Cache-Speicher auf über 512 Cache-Blöcke anwächst. Sie können die minimale Cache-Größe mithilfe der Eigenschaft DataStore.MinCacheSize festlegen. HINWEIS: Ändern Sie die Cache-Größe für JDataStore-Datenbanken nicht willkürlich. Stellen Sie zuvor sicher, dass dadurch die Leistungsfähigkeit Ihrer Anwendung verbessert wird. Denken Sie beim Ändern der Cache-Größe für Blackfish SQL an Folgendes: 130 11 Blackfish SQL • Die Cache-Größe ist bei modernen Betriebssystemen üblicherweise auf hohe Leistungsfähigkeit ausgelegt. In vielen Fällen wird durch das Vergrößern des Cache-Speichers für Blackfish SQL keine merkliche Leistungssteigerung erreicht und nur zusätzlicher Speicher belegt. • Es gibt nur einen Blackfish SQL-Festplatten-Cache für alle bei einem Prozess geöffneten Blackfish SQL-Datenbanken. Wenn alle Blackfish SQL-Datenbanken geschlossen werden, wird der Speicher für diesen globalen Festplatten-Cache freigegeben. • Setzen Sie für Handheld-Geräte mit wenig Speicher die Eigenschaft DataStore.MinCacheSize auf einen niedrigeren Wert, beispielsweise "96". Dateizugriff optimieren Blackfish SQL-Datenbanken führen die meisten Lese-/Schreibvorgänge für die folgenden vier Dateitypen aus: • Die eigentliche Blackfish SQL-Datenbankdatei (mit der Dateierweiterung .jds), die von der Eigenschaft DataStore.FileName festgelegt wird. • Transaktionale Blackfish SQL-Protokolldateien (Dateinamenerweiterung ist LOGAnnnnnnnnnn, wobei n eine Ziffer ist), wie in der TxManager.ALogDir-Eigenschaft angegeben • Temporäre Dateien für umfangreiche Sortiervorgänge, die durch die Eigenschaft DataStore.TempDirName festgelegt sind. • Temporäre .jds-Dateien für SQL-Abfrageergebnisse, die durch die Eigenschaft DataStore.TempDirName festgelegt sind. Die Leistungsfähigkeit kann möglicherweise erhöht werden, wenn Sie Blackfish SQL anweisen, die genannten Dateien auf unterschiedlichen Laufwerken zu plazieren. Dateispeicherung Nachfolgend finden Sie einige Richtlinien zur Dateispeicherung, die die Leistung Ihrer Anwendungen erhöhen können: • Insbesondere ist es wichtig, die Protokolldateien auf einem getrennten Festplattenlaufwerk zu speichern. Protokolldateien werden in der Regel in sequentieller Reihenfolge angehängt und ihr Inhalt wird auf Platte gespeichert, damit Bestätigungsvorgänge (commits) abgeschlossen werden können. Daher ist es vorteilhaft, wenn ein Festplattenlaufwerk zur Verfügung steht, auf dem Schreibvorgänge schnell durchgeführt werden können. • Auf Win32-Plattformen kann die Leistung erhöht werden, indem die Blackfish SQL-Protokolldateien in einem separaten Verzeichnis gespeichert werden. Das Speichern zahlreicher Dateien im Protokolldateiverzeichnis, bei denen es sich nicht um Protokolldateien handelt, kann die Leistung von Commit-Operationen verlangsamen. Dies verbessert eventuell auch auf anderen Plattformen als Windows NT/2000/XP die Performance. • Vergessen Sie nicht, Ihre Festplattenlaufwerke regelmäßig zu defragmentieren. Dies ist insbesondere bei dem Festplattenlaufwerk von Bedeutung, auf dem die Protokolldateien gespeichert sind, weil Blackfish SQL viele sequentielle Lese-/Schreibvorgänge an diesen Dateien durchführt. • Bei Win32-Plattformen sollten Sie die Verwendung eines FAT32-Dateisystems mit einem großen Cluster, z. B. 64 KB für das Laufwerk, in das Ihre Protokolldateien geschrieben werden, in Betracht ziehen. Plattencache-Schreiboptionen bei nicht transaktionalen Datenbanken Hinweis: Dieser Abschnitt gilt nur für Blackfish SQL für Java, das die DataExpress-JavaBean-Komponenten verwendet. 11 Mit der saveMode-Eigenschaft der DataStore-Komponente können Sie überwachen, mit welcher Häufigkeit Cache-Blöcke auf die Festplatte geschrieben werden. Diese Eigenschaft ist nur für nicht transaktionale Blackfish SQL-Datenbanken relevant. Hier die gültigen Werte für diese Methode: 0 Bei diesem Wert überlassen Sie dem Daemon-Thread die Überwachung der Cache-Schreibvorgänge. Bei dieser Einstellung ist die Verarbeitungsgeschwindigkeit am höchsten, gleichzeitig aber auch die Gefahr der Datenbeschädigung. 1 Mit diesem Wert werden die Blöcke sofort beim Hinzufügen oder Löschen gespeichert; der Daemon-Thread übernimmt die Verwaltung aller anderen Änderungen. Dies ist der Standardmodus. Die Verarbeitungsgeschwindigkeit ist annähernd so gut wie im Modus saveMode(0). 131 Blackfish SQL 11 2 Speichert alle Änderungen sofort: Verwenden Sie diese Einstellung immer, wenn Sie eine Anwendung debuggen, die eine DataStore-Komponente verwendet. Im Gegensatz zu anderen Eigenschaften von DataStore kann saveMode auch bei geöffneter Verbindung geändert werden. Wenn Sie beispielsweise eine DataStoreConnection verwenden, können Sie über die dataStore-Eigenschaft auf den Wert zugreifen: DataStoreConnection store = new DataStoreConnection(); ... store.getDataStore().setSaveMode(2); Beachten Sie, dass sich dadurch das Verhalten aller Objekte des Typs DataStoreConnection ändert, die auf die betreffende Blackfish SQL-Datenbankdatei zugreifen. Speicher optimieren Sie können den Speicherbedarf auf verschiedene Arten optimieren. Bedenken Sie jedoch, dass das Reservieren von zu viel Speicher ebenso von Nachteil sein kann wie umgekehrt das Reservieren von zu wenig Speicher. • Sie können auch versuchen, den Wert der Eigenschaft ConnectionProperties.MinCacheBlocks zu erhöhen. Dieser Wert steuert die Mindestanzahl der zwischengespeicherten Blöcke. • Die Eigenschaft ConnectionProperties.MaxSortBuffer steuert die maximale Größe des Puffers, der für Sortierungen im Arbeitsspeicher verwendet wird. Sortierungen, die diese Puffergröße überschreiten, verwenden dann eine langsamere platten-basierte Sortierung. Java-spezifisches Speicher-Tuning Normalerweise wehrt sich der Java-Heap gegen ein Anwachsen über die anfängliche Größe hinaus, indem er immer häufiger Speicherbereinigungen erzwingt, mit der Folge, dass der für den Heap verfügbare Platz immer knapper wird. Mit der JVM-Option -Xms können Sie einen größeren anfänglichen Heap-Umfang definieren. Es ist oft von Vorteil, für die JVM-Einstellungen -Xms und -Xmx dieselben Werte zu wählen. Verschiedene Tipps zur Performance-Steigerung Nachfolgend einige Tipps, wie Sie die Leistung verbessern können: • Es ist oft hilfreich, die Eigenschaft ConnectionProperties.TempDirName, die von der Abfrage-Engine verwendet wird, auf ein Verzeichnis einer anderen (schnelleren) Festplatte zu setzen. • Ändern Sie die Prüfpunktfrequenz für den Transaktions-Manager. Ein höherer Wert kann zu einer besseren Performance führen, sich gleichzeitig aber auch negativ auf das Crash Recovery auswirken. Diese Einstellung kann mithilfe der integrierten gespeicherten Prozedur DB_ADMIN.ALTER_DATABASE per SQL aktualisiert werden. In Blackfish SQL für Java können Sie den JdsExplorer verwenden, um diese Eigenschaft zu setzen, indem Sie TxManager > Ändern auswählen. Transaktionale Anwendungen optimieren 11 Die erhöhte Zuverlässigkeit und Flexibilität, die aus der Verwendung transaktionaler Blackfish SQL-Datenbanken erwachsen, geht teilweise zu Lasten der Verarbeitungsgeschwindigkeit. Sie können dies auf unterschiedliche Weise verhindern, wie in den folgenden Abschnitten beschrieben. Nur-Lese-Transaktionen verwenden Bei Transaktionen, die nur lesen und niemals schreiben, lässt sich durch Nur-Lese-Transaktionen eine erhebliche Steigerung der Verarbeitungsgeschwindigkeit erzielen. Die Verbindungseigenschaft readOnly kontrolliert, ob es eine Nur-Lese-Transaktion ist. Die DataStoreConnection-JavaBean von Blackfish SQL für Java hat eine readOnlyTx-Eigenschaft zum Aktivieren von Nur-Lese-Transaktionen. Bei Nur-Lese-Transaktionen wird eine "Momentaufnahme" der Blackfish SQL-Datenbank simuliert. Diese Momentaufnahme 132 11 Blackfish SQL sieht nur Daten von Transaktionen, die beim Starten der Nur-Lese-Transaktion bestätigt wurden. Die Momentaufnahme wird beim Öffnen der DataStoreConnection erstellt und bei jedem Aufruf einer commit-Methode aktualisiert. Nur-Lese-Transaktionen bieten darüber hinaus den Vorteil, dass sie durch andere Schreib- und Lesevorgänge nicht blockiert werden können. Sowohl zum Lesen als auch zum Schreiben ist normalerweise eine Sperre erforderlich. Da jedoch für eine Nur-Lese-Transaktion eine Momentaufnahme verwendet wird, sind keine Sperren erforderlich. Sie können die Anwendung weiter optimieren, indem Sie einen Wert für die Eigenschaft readOnlyTxDelay definieren. Mit der readOnlyTxDelay-Eigenschaft wird die maximale Lebensdauer einer Momentaufnahme (in Millisekunden) festgelegt, die von der Verbindung genutzt werden kann. Hat diese Eigenschaft nicht den Wert Null, werden bereits vorhandene Momentaufnahmen in absteigender Aktualität (von der neuesten zur ältesten) durchsucht. Wenn eine Momentaufnahme existiert, deren Lebensdauer den Wert readOnlyTxDelay noch nicht überschritten hat, wird diese Momentaufnahme verwendet und eine neue erfasst. Standardmäßig ist diese Eigenschaft auf 5000 Millisekunden gesetzt. Soft-Commit-Modus Wenn Sie den Soft-Commit-Modus über die SoftCommit-Eigenschaft aktivieren, erstellt die Transaktionsverwaltung weiterhin Protokolldatensätze für bestätigte Transaktionen, verwendet aber keinen synchronen Schreibmechanismus für Bestätigungsoperationen. Wenn der Soft-Commit-Modus aktiviert ist, können durch bestätigte Transaktionen geänderte Dateien (file writes) vom Cache-Speicher des Betriebssystems zwischengespeichert werden. In der Regel schreibt das Betriebssystem "Dirty"-Cache-Blöcke innerhalb von Sekunden auf Platte. Der Soft-Commit-Modus führt zu einer Leistungssteigerung, kann aber nicht gewährleisten, dass die zuletzt bestätigten Transaktionen auch wirklich dauerhaft sind. Sie können die SoftCommit-Eigenschaft setzen, indem Sie die integrierte gespeicherte Prozedur DB_ADMIN.ALTER_DATABASE aufrufen. Statusprotokollierung für Transaktionsprotokolldateien deaktivieren Sie können die Verarbeitungsgeschwindigkeit dadurch erhöhen, dass Sie die Protokollierung der ausgegebenen Statusmeldungen deaktivieren. Setzen Sie dazu die recordStatus-Eigenschaft auf false. Sie können die RecordStatus-Eigenschaft setzen, indem Sie die integrierte gespeicherte Prozedur DB_ADMIN.ALTER_DATABASE aufrufen. Die Leistungsfähigkeit der Concurrency-Steuerung von Blackfish SQL verbessern Mithilfe der folgenden Richtlinien können Sie die Leistungsfähigkeit der Concurrency-Steuerungsvorgänge von Blackfish SQL optimieren: • Wählen Sie die niedrigste Isolationsebene, auf der Ihre Anwendung fehlerfrei funktionieren kann. Bei Verwendung niedrigerer Isolationsebenen treten in der Regel weniger und schwächere Sperrungen auf. • Fassen Sie mehrere Anweisungen in einer einzelnen Transaktion zusammen. Bei Verbindungen wird nach jeder Ausführung einer Anweisung standardmäßig das "Commit" des Autocommit-Modus ausgeführt. • Bestätigen ("Commit") Sie Transaktionen so schnell wie möglich. Die meisten Sperrungen werden erst aufgehoben, wenn eine Transaktion bestätigt oder rückgängig gemacht wird. • Verwenden Sie Anweisungs- oder Befehlsobjekte möglichst oft, oder verwenden Sie besser Prepared-Anweisungen oder -Befehle. • Schließen Sie alle Anweisungen oder Befehle, alle Ergebnismengen bzw. Leser und alle Verbindungsobjekte, wenn sie nicht länger benötigt werden. Unidirektionale ResultSet- oder Leserobjekte werden nach dem Lesen der letzten Zeile automatisch geschlossen. • Verwenden Sie Nur-Lese-Transaktionen für Berichte mit langer Ausführungsdauer oder Online-Sicherungsvorgänge. Verwenden Sie die DB_ADMIN.COPYDATABASE-Methode für Online-Backups. Nur-Lese-Transaktionen ermöglichen eine konsistente (serialisierbare), schreibgeschützte Ansicht der Tabellen, auf die sie zugreifen. Sie fordern keine Sperrungen an, weshalb keine Sperr-Zeitüberschreitungen und Deadlocks auftreten können. Weitere Informationen hierzu finden Sie im Abschnitt Nur-Lese-Transaktionen verwenden. • Die Verwaltung einer schreibgeschützten Ansicht erzeugt eine gewisse Menge an Overhead. Daher können mehrere Transaktionen dieselbe schreibgeschützte Ansicht gemeinsam nutzen. Die Eigenschaft ConnectionProperties.ReadOnlyTxDelay gibt an, wie alt die schreibgeschützte Ansicht sein darf, wenn eine Nur-Lese-Transaktion gestartet wird. Bestätigen Sie die Transaktion einer Nur-Lese-Verbindung, um deren Ansicht der 133 11 Blackfish SQL 11 Datenbank zu aktualisieren. Nur-Lese-Transaktionen verwenden die transaktionalen Protokolldateien zum Verwalten ihrer Ansichten. Daher sollten Nur-Lese-Verbindungen geschlossen werden, sobald sie nicht mehr benötigt werden. Vorgänge mit mehreren Threads verwenden Der Durchsatz von Schreibtransaktionen kann erhöht werden, wenn mehr Threads zur Durchführung von Vorgängen verwendet werden, weil alle Threads durch die von Blackfish SQL bereitgestellte “group commit”-Unterstützung den Overhead von Bestätigungsvorgängen gemeinsam nutzen können. Zum Einsatz bereitgestellte Ressourcen für Blackfish SQL für Java-Anwendungen ausdünnen Beim Deployment einer Blackfish SQL-Anwendung können Sie bestimmte, nicht benötigte Klassen und Grafikdateien ausschließen. • Wenn Blackfish SQL ohne JDBC-Treiber verwendet wird, schließen Sie folgende Klassen aus: • com.borland.datastore.Sql*.class • com.borland.datastore.jdbc.* • com.borland.datastore.q2.* • Wenn Sie DataExpress verwenden und die Eigenschaft StorageDataSet.store immer auf eine Instanz von DataStore oder DataStoreConnection gesetzt ist, schließen Sie folgende Klassen aus: • com.borland.dx.memorystore.* • Wenn StorageDataSet verwendet wird, nicht jedoch QueryDataSet, QueryProvider, StoredProcedureDataSet oder StoredProcedureProvider, schließen Sie folgende Klassen aus: • com.borland.dx.sql.* • Wenn der Datenzugriff keine visuellen Komponenten aus den JBCL- oder dbSwing-Bibliotheken verwendet, schließen Sie folgende Klassen aus: • com.borland.dx.text.* • Wenn com.borland.dx.dataset.TextDataFile nicht verwendet wird, schließen Sie folgende Klassen aus: • com.borland.jb.io.* • com.borland.dx.dataset.TextDataFile.class • com.borland.dx.dataset.SchemaFile.class AutoIncrement-Spalten Spalten vom Typ int und long können jetzt als AutoIncrement-Werte angegeben werden. Folgende Eigenschaften treffen auf alle Werte in AutoIncrement-Spalten zu: • Sie sind immer eindeutig • Sie dürfen nicht leer sein • Werte aus gelöschten Zeilen können nie wiederverwendet werden 11 Durch diese Attribute eignen sich AutoIncrement-Spalten optimal für einspaltige Primärschlüssel vom Typ integer/long. Bei AutoIncrement-Spalten handelt es sich um den "internal row"-Bezeichner einer Zeile. Daher bieten sie den schnellstmöglichen Direktzugriffspfad zu einer bestimmten Zeile in einer Blackfish SQL-Tabelle. Jede Tabelle kann eine AutoIncrement-Spalte enthalten. Wenn Sie die AutoIncrement-Spalte als Ersatz für Ihren Primärschlüssel verwenden, wird der Platz einer Ganzzahlspalte und eines sekundären Indexes in Ihrer Tabelle eingespart. Der Blackfish SQL Query Optimizer optimiert Abfragen, die auf eine AutoIncrement-Spalte in einer WHERE-Klausel verweisen. Anweisungen zur Verwendung der AutoIncrement-Spalten mit SQL finden Sie unter “AutoIncrement-Spalten mit SQL verwenden” in der SQL-Referenz. 134 11 Blackfish SQL AutoIncrement-Spalten unter Verwendung von DataExpress-JavaBeans von Blackfish SQL für Java Um mit DataExpress eine Tabelle mit einer AutoIncrement-Spalte zu erstellen, setzen Sie die Eigenschaft Column.AutoIncrement auf true, bevor Sie eine Tabelle öffnen. Wenn Sie eine vorhandene Tabelle ändern möchten, müssen Sie die Methode StorageDataSet.restructure() aufrufen. Blackfish SQL-Companion-Komponenten Die dbSwing-Komponentenbibliothek enthält zwei Komponenten (auf der Registerseite Komponentenpalette), die die Erstellung von robusten Blackfish SQL-Anwendungen erleichtern. Mehr dbSwing in der • DBDisposeMonitor entfernt beim Schließen von Containern automatisch datensensitive Komponentenressourcen. Die Komponente verfügt über eine closeDataStores-Eigenschaft. Wenn die Eigenschaft den Wert true (Vorgabe) hat, werden alle Blackfish SQL-Datenbanken, die mit den von dieser Eigenschaft bereinigten Komponenten verbunden sind, automatisch geschlossen. Wenn Sie beispielsweise die Komponente DBDisposeMonitor in einen von Ihnen bearbeiteten JFrame ziehen, der mit einer Blackfish SQL-Datenbank verbundene dbSwing-Komponenten enthält, schließt DBDisposeMonitor automatisch die Blackfish SQL-Datenbank für Sie, wenn Sie JFrame schließen. Diese Komponente ist besonders praktisch, wenn Sie zum Experimentieren mit Blackfish SQL einfache kleine Anwendungen erstellen. • DBExceptionHandler verfügt über einen Schalter zum Beenden. Dieser ist standardmäßig sichtbar, Sie können ihn aber über benutzerdefinierte Einstellungen verbergen. Wenn Sie auf diesen Schalter klicken, werden alle geöffneten Blackfish SQL-Datenbankdateien, die gefunden werden, automatisch geschlossen.DBExceptionHandler ist das Standard-Dialogfeld, das von dbSwing-Komponenten angezeigt wird, wenn eine Exception auftritt. Datenmodule für DataExpress-JavaBean-Komponenten von Blackfish SQL für Java verwenden Beim Verwenden einer Blackfish SQL-Tabelle mit einem StorageDataSet sollten Sie in Erwägung ziehen, alle Komponenten in Datenmodulen zu gruppieren. Aktualisieren Sie alle Referenzen auf diese StorageDataSets mithilfe von DataModule-Zugriffsmethoden, wie z. B. businessModule.getCustomer. Der Grund dafür ist, dass ein Großteil der durch StorageDataSets bereitgestellten Funktionen durch Eigenschafts- und Ereigniseinstellungen gesteuert wird. Obwohl die meisten wichtigen strukturellen StorageDataSet-Eigenschaften in der Blackfish SQL-Tabelle selbst in beständiger Form vorhanden sind, gilt dies nicht für die Klassen, die die Ereignis-Listener-Schnittstellen implementieren. Durch das Instantiieren des StorageDataSets mit allen Ereignis-Listenern, Begrenzungen, berechneten Feldern und Filtern, die durch Ereignisse implementiert werden, wird sichergestellt, dass diese zur Laufzeit und in der Entwurfsphase korrekt verwaltet werden. Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( 11 see page 57) see page 61) see page 77) Deployment von Blackfish SQL-Datenbankanwendungen ( Fehlersuche ( see page 43) see page 137) see page 141) 135 12 Blackfish SQL 12 Deployment von Blackfish SQL-Datenbankanwendungen Wenn Sie mit dem Entwickeln Ihrer Anwendung fertig sind, ist der nächste Schritt das Deployment it. Das Deployment umfasst Überlegungen zur Lizenzierung und das Ermitteln, welche Blackfish SQL-Dateien für die Verteilung erforderlich sind. In diesem Kapitel behandelt die Blackfish SQL-Distributionsdateien. Falls Sie weitere Informationen hinsichtlich der Deployment-Lizenz benötigen, kontaktieren Sie den Kunden-Support. • Deployment von Blackfish SQL für Windows-Anwendungen • Deployment von Blackfish SQL für Java-Anwendungen Deployment von Blackfish SQL für Windows-Anwendungen Welche Dateien für die Verteilung erforderlich sind, ist von dem Anwendungstyp abhängig, den Sie entwickelt haben. Die nachfolgende Tabelle bietet einige Richtlinien zur Ermittlung der zu verteilenden Dateien. Deployment-Dateien für Blackfish SQL für Windows-Anwendungen Dateiname Beschreibung DbxClientDriver100.bpl DbxCommonDriver100.bpl DbxReadOnlyMetaData100.bpl Remote-dbExpress-Treiber für Win32-Anwendungen, die Pakete verwenden. Falls Sie keine Pakete verwenden, wird der Treiber mit der .exe-Datei der Anwendung verlinkt. Borland.Data.DbxClientDriver.dll Borland.Data.DbxCommonDriver.dll Borland.Data.DbxReadOnlyMetaData.dll Remote-dbExpress-Treiber für .NET-Anwendungen, die Assemblies verwenden. Falls Sie keine Assemblies verwenden, wird der Treiber mit der .exe-Datei der Anwendung verlinkt. Borland.Data.BlackfishSQL.LocalClient.dll .NET-Assembly, das den lokalen ADO.NET-Provider und den Datenbankkernel selbst enthält. Dies ist die einzige erforderliche Datei für Anwendungen, die nur den lokalen ADO.NET-Provider verwenden. Borland.Data.BlackfishSQL.RemoteClient.dll .NET-Assembly, das den Remote-ADO.NET-Provider enthält. BSQLServer.exe BSQLServer.exe.config Startprogramme, die zum Starten des Servers von der Befehlszeile aus oder als Windows-Dienst benötigt werden. Sie müssen zusammen mit diesen Dateien auch Borland.Data.BlackfishSQL.LocalClient.dll zum Einsatz bereitstellen. 137 12 Blackfish SQL 12 Deployment von Lizenzen für Blackfish SQL für Windows Blackfish SQL für Windows durchsucht folgende Speicherorte nach SLIP-Lizenzdateien: • Die blackfishsql.licenseDirectory-Systemeigenschaft Legen Sie diese Eigenschaft durch Aufruf der System.AppDomain.CurrentDomain.SetData-Methode oder durch Angabe einer Einstellung für diese Eigenschaft in der Datei BSQLServer.exe.config fest. • Das Verzeichnis des Servers, wenn Sie einen Remote-Treiber verwenden • Das Verzeichnis der .exe-Datei der Anwendung, die einen lokalen Treiber verwendet • Der GAC-Speicherort des Assembly, wenn der lokale Treiber in Gebrauch ist und zum GAC hinzugefügt wurde • Das CodeGear-Unterverzeichnis des Ordners System.Environment.SpecialFolder.CommonApplicationData • $(BDSCOMMONDIR)\license Die BDSCOMMONDIR-Umgebungsvariable wird gesetzt, wenn BDS installiert ist. Deployment von Blackfish SQL für Java-Anwendungen Blackfish SQL enthält eine Vielzahl unterschiedlicher JAR-Dateien. Welche Dateien für die Verteilung erforderlich sind, ist von dem Anwendungstyp abhängig, den Sie entwickelt haben. Die nachfolgende Tabelle bietet einige Richtlinien zur Ermittlung der zu verteilenden Dateien. JAR-Dateien für das Deployment von Blackfish SQL für Java-Anwendungen Dateiname Beschreibung dx.jar Lokale DataExpress-Datenbank-Konnektivität jds.jar Lokale JDBC-Datenbank-Konnektivität jdsremote.jar Externe JDBC-Thin-Client-Datenbank-Konnektivität jdsserver.jar Vollständig eingebetteter Laufzeit-Datenbank-Server Remote-JDBC-Datenbank-Konnektivität jdshelp.jar jdsserver.jar beandt.jar für lokale und dbtools.jar Erforderlich für die grafischen Benutzeroberflächen von JdsServer und JdsExplorer beandt.jar Erforderlich für das Compilieren und das visuelle Design von Java Bean-Komponenten dbswing.jar Erforderlich für Swing-basierte Benutzeroberflächen jbcl-awt.jar Erforderlich für AWT-basierte Benutzeroberflächen <BlackfishSQL_home>/bin/JdsServer Windows: JdsServer.exe Startprogramm für die Benutzeroberfläche des Blackfish SQL-Servers JdsServer.config Konfigurationsdatei für das JdsServer-Startprogramm <BlackfishSQL_home>/bin/JdsExplorer Startprogramm für die Benutzeroberfläche des JdsExplorers Windows: JdsExplorer.exe JdsExplorer.config Konfigurationsdatei für das JdsExplorer-Startprogramm <BlackfishSQL_home>/doc/* Das Blackfish SQL-Hilfesystem, das direkt oder über JdsExplorer oder JdsServer aufgerufen werden kann 12 Deployment von Lizenzen für Blackfish SQL für Java Blackfish SQL für Java durchsucht folgende Speicherorte nach SLIP-Lizenzdateien: • Die blackfishsql.licenseDirectory-Systemeigenschaft 138 12 Blackfish SQL Sie können diese Eigenschaft durch Aufruf der java.lang.System.setProperty-Methode festlegen. Geben Sie diese Eigenschaft mit der -D-Option in der Befehlszeile der Java Virtual Machine an: -DblackfishSQL.licenseDirectory=/mylicenseDir Alternativ können Sie diese Eigenschaft in der Datei JdsServer.config durch Hinzufügen einer vmparam -D-Anweisung setzen: vmparam -DblackfishSQL.licenseDirectory=/mylicenseDir • Die Java-Systemeigenschaft user.home • Alle in der Java-Einstellung classpath angegebenen Verzeichnisse Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( Fehlersuche ( see page 43) see page 129) see page 141) 12 139 13 Blackfish SQL 13 Fehlersuche In diesem Kapitel werden einige Richtlinien zur Fehlersuche und zum Auflösen von Fehlerbedingungen bzw. zum Lösen anderer Probleme aufgeführt, die beim Erstellen und Verwalten von Blackfish SQL-Datenbanken sowie beim Zugriff auf diese auftreten können. • Relativer Pfad für Datenbankdateinamen • Blackfish SQL-Systemprotokollierung aktivieren • Blackfish SQL-Datenbankprotokollierung aktivieren • Zeitüberschreitungen bei Sperren und Deadlocks debuggen • Integrität einer Blackfish SQL-Datenbank verifizieren • Fehlersuche bei Blackfish SQL für Java Relativer Pfad für Datenbankdateinamen Sie können das DataDirectory-Makro in der Spezifikation von Datenbankdateinamen verwenden, um Unterstützung für relative Pfadnamen zu ermöglichen. Weitere Informationen zum DataDirectory-Makro finden Sie unter Verbindungen aufbauen. Wenn Sie das DataDirectory-Makro nicht verwenden, sind relative Pfadnamen relativ zum aktuellen Verzeichnis des Prozesses, in dem Blackfish SQL ausgeführt wird. Auf Java-Plattformen gibt die Eigenschaft user.dir an, wie Datenbankdateinamen aufgelöst werden, wenn kein voll qualifizierter Pfadname angegeben wurde. Die JVM legt für diese Eigenschaft das aktuelle Arbeitsverzeichnis des Prozesses als Standard fest. Sie können diese Eigenschaft mit einer JVM.Befehlszeilenoption festlegen. Beispiel: -Duser.dir=/myapplication Sie können diese Eigenschaft auch in einer java.util.System.setProperty-Methode verwenden. Java-Anwendung festlegen, indem Sie die Blackfish SQL-Systemprotokollierung aktivieren Die Systemprotokollierung wird für alle Verbindungen und alle Datenbanken durchgeführt, auf die in demselben Prozess zugegriffen wird. Sie können die Blackfish SQL-Systemprotokollierung auf folgenden Arten aktivieren. Für den lokalen Blackfish SQL-Client: Setzen Sie die Systemeigenschaft blackfishsql.logFile auf den Namen der Datei, in die die Protokollausgabe geschrieben werden soll. Wenn Sie die Eigenschaft auf con setzen, wird die Protokollausgabe in der Konsole angezeigt. Sie 141 13 Blackfish SQL 13 können die Operationsarten angeben, die in der Protokolldatei protokolliert werden sollen, indem Sie die Eigenschaft blackfishsql.logFilters setzen. Für den Blackfish SQL-Remote-Client: Setzen Sie in der Blackfish SQL-Konfigurationsdatei die Eigenschaft blackfishsql.logFile auf den Namen der Datei, in die die Protokollausgabe geschrieben werden soll. Wenn Sie die Eigenschaft auf con setzen, wird die Protokollausgabe in der Konsole angezeigt. Sie können die Operationsarten angeben, die in der Protokolldatei protokolliert werden sollen, indem Sie die Eigenschaft blackfishsql.logFilters setzen. Systemeigenschaften einstellen Bei allen Blackfish SQL-Systemeigenschaften muss die Groß-/Kleinschreibung beachtet werden und allen Eigenschaften ist das Präfix blackfishsql. vorangestellt. Die Klasse SystemProperties verwendet String-Konstanten für alle Systemeigenschaften. Für Windows-Systemeigenschaften: Wenn Ihre Anwendung den Blackfish SQL-Server verwendet, legen Sie die Systemeigenschaften in der Datei BSQLServer.exe.config fest. Wenn Ihre Anwendung den Blackfish SQL-Server nicht verwendet, legen Sie die Systemeigenschaften durch Aufrufen der Methode System.AppDomain.CurrentDomain.SetData fest. Für Java-Systemeigenschaften: Wenn Ihre Anwendung den Blackfish SQL-Server verwendet, legen Sie die Systemeigenschaften in der Datei BSQLServer.config fest und stellen Sie der Eigenschaftseinstellung das Präfix vmparam -D voran. Wenn Ihre Anwendung den Blackfish SQL-Server nicht verwendet, legen Sie die Systemeigenschaften durch Aufrufen der Methode System.setProperty fest. Blackfish SQL für Java - JDBC-Protokollierungsoptionen Dies sind zusätzliche Protokollierungsoptionen für Blackfish SQL für Java: • Wenn Sie eine javax.sql.DataSource-Implementierung verwenden, rufen Sie die setLogWriter-Methode der DataSource-Implementierung auf. Weitere Informationen finden Sie unter com.borland.javax.sql.JdbcDataSource und com.borland.javax.sql.JdbcConnectionPool. • Rufen Sie die java.sql.DriverManager.setLogStream-Methode auf. • Rufen Sie die java.sql.DriverManager.setLogWriter-Methode auf. Blackfish SQL-Datenbankprotokollierung aktivieren Die Ausgabe der Datenbankprotokollierung erfolgt pro Datenbank und wird an die Statusprotokolldateien für die jeweilige Datenbank gesendet. Statusprotokolldateien werden auf dieselbe Weise verwaltet wie die Transaktionsprotokolldateien der Datenbank. Wenn eine Transaktionsprotokolldatei gelöscht wird, wird die entsprechendee Statusprotokolldatei ebenfalls gelöscht. Wenn Sie eine Datenbank erstellen, wird die Statusprotokollierung standardmäßig deaktiviert. Sie können die Statusprotokollierung von Datenbanken aktivieren, indem Sie die integrierte gespeicherte Prozedur DB_ADMIN.ALTER_DATABASE aufrufen. Sie können die Protokollfilteroptionen für alle Verbindungen zu einer Datenbank einstellen, indem Sie die integrierte gespeicherte Prozedur DB_ADMIN.SET_DATABASE_STATUS_LOG_FILTER aufrufen. Die Protokollfilteroptionen für eine einzelne Verbindung werden gesetzt, indem Sie die Verbindungseigenschaft logFilter einstellen oder indem Sie die integrierte gespeicherte Prozedur DB_ADMIN.SET_STATUS_LOG_FILTER aufrufen. Zeitüberschreitungen bei Sperren und Deadlocks debuggen 13 Sperren können aufgrund einer Zeitüberschreitung oder eines Deadlocks fehlschlagen. Zeitüberschreitungen bei Sperren treten ein, wenn eine Verbindung auf eine angeforderte Sperrung, die von einer anderen Transaktion aufrechterhalten wird, länger als die Anzahl an Millisekunden warten muss, die in der Verbindungseigenschaft lockWaitTime festgelegt ist. In solchen Fällen wird eine Exception ausgelöst, die angibt, bei welcher Verbindung die Zeitüberschreitung aufgetreten ist und welche Verbindung die erforderliche Sperrung aktuell aufrechterhält. Die Transaktion, bei der die Zeitüberschreitung auftritt, wird nicht rückgängig gemacht (kein Rollback). 142 13 Blackfish SQL Blackfish SQL verfügt über eine automatische Deadlock-Erkennung, die alle Deadlocks erkennt. Es wird eine entsprechende Exception ausgelöst, die angibt, bei welcher Verbindung ein Deadlock aufgetreten ist und mit welcher Verbindung dieser Konflikt besteht. Im Gegensatz zu Exceptions bei Sperr-Zeitüberschreitungen führen Deadlock-Exceptions, die bei einer java.sql.Connection auftreten, dazu, dass die Transaktion innerhalb der Verbindung automatisch rückgängig gemacht wird (Rollback). Durch dieses Verhalten können andere Verbindungen fortbestehen. Gehen Sie zum Erkennen von Zeitüberschreitungs- und Deadlock-Situationen folgendermaßen vor: • Lesen Sie die Exception, die aufgrund einer Zeitüberschreitung oder eines Deadlocks ausgegeben wird. Die Meldung enthält Informationen zu den betroffenen Tabellen und Verbindungen. • Aktivieren Sie die System- oder Datenbankprotokollierung. Um die Protokollausgabe auf sperrbezogene Meldungen zu beschränken, setzen Sie die Protokollfilteroptionen auf LOCK_ERRORS. • Verwenden Sie die integrierte gespeicherte Prozedur DB_ADMIN.GET_LOCKS zum Melden von Sperren, die von allen Verbindungen aktiviert werden. Sperren und Deadlocks vermeiden Für eine Verbindung ist normalerweise eine Sperrung erforderlich, wenn sie Daten aus einem Tabellenstrom oder einer Zeile liest oder in diese schreibt. Sie kann durch eine andere Verbindung blockiert werden, bei der gelesen oder geschrieben wird. Sperren können Sie auf zweierlei Arten verhindern: • Durch die Verkürzung der Lebensdauer von Schreib-Transaktionen. • Durch die Verwendung von Nur-Lese-Transaktionen, für die zum Lesen keine Sperren erforderlich sind. Kurze Schreib-Transaktionen verwenden In Umgebungen, in denen viele Benutzer gleichzeitig Zugriff benötigen, sollten für Verbindungen kurze Transaktionen verwendet werden. In Umgebungen, in denen nur wenige oder keine Benutzer gleichzeitigen Zugriff benötigen, bieten Transaktionen mit langer Dauer einen besseren Durchsatz, weil weniger Commit-Anforderungen gestellt werden. Eine Commit-Operation ist mit einem erheblichen Overhead verbunden, weil diese die Dauerhaftigkeit einer Transaktion gewährleisten muss. Nur-Lese-Transaktionen verwenden Nur-Lese-Transaktionen können von anderen Lese- oder Schreibvorgängen nicht blockiert werden, und da sie selbst kein Sperre verursachen, sperren sie auch niemals andere Transaktionen. Wenn die Verbindungseigenschaft readOnlyTx auf true gesetzt wird, werden Nur-Lese-Verbindungen verwendet. Beachten Sie, dass es auch eine readOnly-Verbindungseigenschaft gibt, die sich von der readOnlyTx-Verbindungseigenschaft allerdings stark unterscheidet. Durch die readOnly-Verbindungseigenschaft wird die Datenbankdatei im schreibgeschützten Modus geöffnet, was andere Verbindungen daran hindert, in die Datenbank zu schreiben. Bei JDBC-Verbindungen für Blackfish SQL für Java können Sie auch Nur-Lese-Transaktionen aktivieren, indem Sie die readOnly java.sql.Connection Eigenschaft des Objekts oder der Methode com.borland.dx.sql.dataset.Database.getJdbcConnection auf true setzen. Bei Verwendung von Blackfish SQL für Java-Objekten des Typs DataStoreConnection setzen Sie die Eigenschaft readOnlyTx auf true, bevor Sie die Verbindung öffnen. Bei Nur-Lese-Transaktionen wird eine "Momentaufnahme" der Blackfish SQL-Datenbank simuliert. In dieser Momentaufnahme erscheinen nur Daten aus Transaktionen, die beim Starten der Transaktion bereits bestätigt waren. Anderenfalls müsste die Verbindung prüfen, ob noch ausstehende Änderungen vorhanden sind und sie beim Zugriff auf die Daten rückgängig machen. Eine Momentaufnahme wird gemacht, wenn die Verbindung geöffnet wird. Sie wird immer dann aktualisiert, wenn die commit-Methode des Objekts aufgerufen wird. 143 13 Blackfish SQL 13 Integrität einer Blackfish SQL-Datenbank verifizieren Wenn Sie den Verdacht haben, dass der Cache-Inhalt nicht ordnungsgemäß in einer nicht transaktionalen Blackfish SQL-Datenbank gespeichert wurde, können Sie die Integrität der Datei durch Aufruf der integrierten gespeicherten Prozedur DB_ADMIN.VERIFY verifizieren. Beachten Sie, dass beim Öffnen von transaktionalen Blackfish SQL-Datenbanken Crash Recovery automatisch aktiviert wird. Unter normalen Umständen benötigen Blackfish SQL-Datenbanken keine Verifizierung. Fehlersuche bei Blackfish SQL für Java Dieser Abschnitt bietet weitere Richtlinien für die Java-spezifische Fehlersuche. Trigger und gespeicherte Prozeduren debuggen Die Vorgehensweise zum Debuggen von Triggern und gespeicherten Prozeduren hängt davon ab, ob Ihre Anwendung den lokalen oder den externen JDBC-Treiber verwendet. Wenn Ihre Anwendung den lokalen JDBC-Treiber verwendet, müssen keine speziellen Einstellungen vorgenommen werden, weil die Datenbank-Engine denselben Prozess verwendet wie Ihre Anwendung. Wenn Ihre Anwendung den Remote-JDBC-Treiber benutzt, können Sie eines der folgenden Verfahren verwenden. Mithilfe des DataStoreServer-Java Beans debuggen: Instantiieren Sie in Ihrer Anwendung die Java Bean-Komponente com.borland.datastore.jdbc.DataStoreServer und führen Sie deren start-Methode aus. Mithilfe des JdsServers debuggen: Führen Sie die folgenden Schritte aus: 1. Fügen Sie die folgenden Zeilen in die Datei <jds_home>/bin/JdsServer.config ein: vmparam -Xdebug vmparam -Xnoagent vmparam -Djava.compiler=NONE vmparam -Xrunjdwp:transport=dt_socket,server=y,address=5000,suspend=y 2. Führen Sie den JdsServer aus. Der Server wird erst hochgefahren, wenn ein Remote-Debugger (wie der von JBuilder) gestartet und eine Verbindung zum JdsServer-Prozess auf Port 5000 hergestellt wird. Tabellen mithilfe von SQL und DataExpress JavaBeans erstellen und darauf zugreifen Beim Erstellen von SQL-Tabellen (create table) werden Bezeichner ohne Anführungszeichen in Großbuchstaben umgewandelt. Sie müssen die Bezeichner in Anführungszeichen einschließen, damit die Groß-/Kleinschreibung beachtet wird. Weitere Informationen hierzu finden Sie unter “Bezeichner” in der SQL-Referenz. Wenn zum Erstellen einer Tabelle DataExpress-Komponenten verwendet werden, wird bei den Tabellen- und Spaltennamen die Groß- und Kleinschreibung beachtet. Wenn für die Bezeichner nur Kleinbuchstaben bzw. Groß- und Kleinbuchstaben verwendet werden, kann in SQL nur auf sie zugegriffen werden, wenn sie in Anführungszeichen gesetzt werden. Wenn mithilfe von DataExpress auf eine Tabelle zugegriffen wird, wird für die storeName-Eigenschaft von StorageDataSet die Groß- und Kleinschreibung beachtet. Für Spaltenbezeichner muss die Groß- und Kleinschreibung jedoch nicht beachtet werden. Bei DataExpress können Sie folglich auf die Spalte adresse sowohl unter Verwendung von ADRESSE als auch von adresse zugreifen. Um Probleme im Zusammenhang mit den Bezeichnern für SQL- und DataExpress-Komponenten zu vermeiden, ist die Verwendung von Großbuchstaben für Bezeichner empfehlenswert, wenn Ihre Anwendung Tabellen erstellt oder darauf zugreift. Nicht transaktionale Datenbankanwendungen debuggen 13 Setzen Sie die saveMode-Eigenschaft auf 2, wenn Sie eine Anwendung debuggen, die eine nicht transaktionale Blackfish 144 13 Blackfish SQL SQL-Datenbank verwendet. Der Debugger hält bei der Einzelschrittverarbeitung und beim Vorfinden von Haltepunkten an. Wenn Sie die saveMode-Eigenschaft nicht auf 2 setzen, kann der Blackfish SQL-Daemon-Thread geänderte Cache-Daten nicht speichern. Weitere Informationen finden Sie unter “Plattencache-Schreiboptionen bei nicht transaktionalen Datenbanken” im Kapitel Blackfish SQL-Anwendungen optimieren. Probleme beim Auffinden und Sortieren von Daten lösen Sun Microsystems ändert von Zeit zu Zeit die java.text.CollationKey-Klassen, um Probleme zu beheben. Die Sekundärindizes für in Blackfish SQL-Datenbanken gespeicherte Tabellen verwenden diese CollationKey-Klassen zum Generieren von sortierbaren Schlüsseln für Sprachräume außerhalb der USA. Wenn Sun das Format dieser CollationKeys ändert, funktionieren die von älteren Sun JDKs erstellten Sekundärindizes bei einem neuen Sun JDK unter Umständen nicht mehr richtig. Die daraus entstehenden Probleme machen sich folgendermaßen bemerkbar: • Such- und Abfrageoperationen finden Datensätze, die sie finden müssten, nicht mehr. • Beim Anzeigen einer Tabelle in der Reihenfolge der Sekundärindizes (durch Setzen der StorageDataSet.sort-Eigenschaft) stimmt unter Umständen die Sortierfolge nicht. Gegenwärtig besteht die einzige Abhilfe für dieses Problem darin, die Sekundärindizes zu verwerfen und mit dem aktuellen JDK neu zu erstellen. Die Methode StorageDataSet.restructure() entfernt auch alle sekundären Indizes. Siehe auch Vorwort ( Übersicht ( see page 1) see page 3) Systemarchitektur ( see page 7) Verbindungen aufbauen ( see page 25) Administration von Blackfish SQL ( see page 33) Sicherheitsfunktionen von Blackfish SQL ( see page 37) Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden ( Trigger in Blackfish SQL-Tabellen verwenden ( Gespeicherte Prozeduren - Referenz ( SQL-Referenz ( see page 43) see page 57) see page 61) see page 77) Blackfish SQL-Anwendungen optimieren ( see page 129) Deployment von Blackfish SQL-Datenbankanwendungen ( see page 137) 13 145 14 Blackfish SQL Index A Administration von Blackfish SQL 33 B Blackfish SQL-Anwendungen optimieren 129 D DB_ADMIN 61 DB_UTIL 61 Deployment von Blackfish SQL-Datenbankanwendungen 137 F Fehlersuche 141 G Gespeicherte Prozeduren - Referenz 61 Gespeicherte Prozeduren und benutzerdefinierte Funktionen verwenden 43 S Sicherheitsfunktionen von Blackfish SQL 37 SQL-Referenz 77 Systemarchitektur 7 T Trigger in Blackfish SQL-Tabellen verwenden 57 Ü Übersicht 3 V Verbindungen aufbauen 25 Vorwort 1 a