11. Oktober 2016

OTN Appreciation Day: The Java VM in the Oracle Database

... nachdem ich auf Twitter die Tweets zum OTN Appreciation Day gelesen habe, möchte ich das auf jeden Fall nutzen, um mal wieder ein Blog Posting zu veröffentlichen. Als Mitglied des APEX-Teams scheidet APEX für mich wohl aus - daher möchte ich auf ein Feature hinweisen, was mich die letzten Jahre immer wieder erstaunt hat: die Java-Engine in der Oracle-Datenbank.

Bereits seit der Version 8i ist Oracle mit einer Java-Engine ausgestattet - das bedeutet, dass man Stored Procedures nicht nur mit PL/SQL - sondern eben auch in Java implementieren kann. In den meisten Fällen, das muss man zugeben, macht das nur wenig Sinn, denn PL/SQL ist für die Arbeit mit SQL und Daten optimiert. Allerdings bietet die Java-Funktionsbibliothek einige Dinge an, die mit PL/SQL gar nicht oder nur schwer machbar sind.

  • Dateisystemzugriffe und Ausführen von Betriebssystem-Kommandos
  • Ausführen von ECMA Skriptsprachen (ab Java7)
  • Zugriffe auf Email-Server (IMAP, POP3)

Eine Java Stored Procedure entsteht, in dem man den Java Code, entweder mit dem Kommando CREATE OR REPLACE JAVA oder mit dem Kommandozeilentool loadjava in die Datenbank lädt. Das coole ist nun, dass man für statische Java-Methoden einen PL/SQL Wrapper erzeugen kann. Die Java-Methode bekommt also eine PL/SQL Schnittstelle: Für den Aufrufer ist alles PL/SQL, tatsächlich ausgeführt wird Java. Dazu ein (wirklich kurzes) Beispiel: Wir wollen für jedes Oracle Data File wissen, wieviel Platz auf dem Device (der Disk) noch vorhanden ist. Auf Unix/Linux wäre das das Kommando df - und das soll es in der Datenbank sein. Für das Beispiel braucht Ihr Oracle12c.

Erstmal die Java Stored Procedure anlegen - am besten macht Ihr das als SYS.

create or replace and compile java source named JAVA_GET_FREESPACE as
import java.io.*;

public class FreeSpaceHelper {
  public static long getFreeSpace(String pPath) throws Exception {
    return new File(pPath).getFreeSpace();
  }
}
/
sho err

create or replace function get_free_disk_space (p_path in varchar2) return number
is language java name 'FreeSpaceHelper.getFreeSpace(java.lang.String) return long';
/
Dann ruft man diese Funktion für jeden Eintrag in DBA_DATA_FILES auf. Fertig.
select 
  file_name, 
  bytes file_size,
  get_free_disk_space(file_name) free_space
from dba_data_files
/
Ein wenig formatiert, sieht der Output so aus ...
FILE_NAME                                          FILE_SIZE       FREE_SPACE
-------------------------------------------------- --------------- -------------
/opt/oracle/oradata/orcl/pdb1/system01.dbf         270MB           22GB
/opt/oracle/oradata/orcl/pdb1/sysaux01.dbf         680MB           22GB
/opt/oracle/oradata/orcl/pdb1/pdb1_users01.dbf     5MB             22GB

Java in der Datenbank bringt eine ganze Menge Möglichkeiten mit - in der Vergangenheit habe ich öfter darüber gebloggt; das eine oder andere steht auch im Internet zum Download bereit. Hier eine kleine Auswahl:

... after reading the tweets about the OTN Appreciation Day, I would like to take the opportunity to publish a posting on this blog again ( I know that this blog needs more postings ;-) ). As a member of the APEX development team, I'm not supposed to talk about APEX, so I decided to choose another of my favorite database topics: The Java engine within the Oracle database. This feature opens so many opportunities, I'm fascinated about this all the time.

Since Oracle8i, the Oracle database comes with an embedded Java engine. It contains the full functionality from a JDK - and allows to implement Stored Procedures in Java. I have to admit: In many cases this simply does not make sense, since PL/SQL is way faster in working with cursors, tables and SQL data types. But, as said, the JVM comes with the full java class library - and that library contains much more functionality than PL/SQL. So the Java engine allows you to to tasks in your database which, in PL/SQL, are either difficult, unsupported or simply not possible.

To create a Java Stored Procedure, load the java code into the database. This can be done either with the CREATE OR REPLACE JAVA SQL command or with the command line utility loadjava. The cool thing is now that you can create a PL/SQL wrapper for any static Java method. I'll illustrate this with a (short, really) example: For each row of the DBA_DATA_FILES view, we want to know, how much space is available on the device (on Linux/Unix we would use df). PL/SQL does not have any call for this - but Java can help (note: you need Oracle 12.1) to run this example. It's best to run as SYS.

First, create the Java Stored Procedure. Then, create the PL/SQL wrapper.

create or replace and compile java source named JAVA_GET_FREESPACE as
import java.io.*;

public class FreeSpaceHelper {
  public static long getFreeSpace(String pPath) throws Exception {
    return new File(pPath).getFreeSpace();
  }
}
/
sho err

create or replace function get_free_disk_space (p_path in varchar2) return number
is language java name 'FreeSpaceHelper.getFreeSpace(java.lang.String) return long';
/
Then call that new "SQL function" for each row of DBA_DATA_FILES.
select 
  file_name, 
  bytes file_size,
  get_free_disk_space(file_name) free_space
from dba_data_files
/
You should see output like this. Done.
FILE_NAME                                          FILE_SIZE       FREE_SPACE
-------------------------------------------------- --------------- -------------
/opt/oracle/oradata/orcl/pdb1/system01.dbf         270MB           22GB
/opt/oracle/oradata/orcl/pdb1/sysaux01.dbf         680MB           22GB
/opt/oracle/oradata/orcl/pdb1/pdb1_users01.dbf     5MB             22GB

The Java engine within the Oracle database offers huge opportunities. Functionality, you might have thought, is impossible to run inside the database, can be easily coded as Java stored procedure. In the past, I authored blog postings about this - here's a tiny choice:

Beliebte Postings