4. Juni 2014

Dateien per FTP in eine (eigene) Tabelle laden - Teil II

Upload files into your table with FTP - just with the database - Part II
In diesem Blog Posting setze ich das beim letzten Mal begonnene Thema FTP-Uploads in eigene Tabellen fort. Im ersten Teil wurden die Protokollserver und die XML DB Repository Events prinzipiell vorgestellt und es wurde gezeigt, wie man, mit Hilfe des Events Pre-Create einen FTP-Upload "abfängt" und in eine eigene Tabelle umleitet. Anschließend befindet sich die hochgeladene Datei in der eigenen Tabelle, während die Datei im XML DB Repository nur noch deren Primärschlüssel enthält. Heute wird dieses Modell erweitert: Wir wollen noch weitere Events implementieren, so dass eine wirklich vollständige FTP-Schnittstelle für unsere Tabelle FILES_TAB entsteht.
  • Pre-Create wurde im ersten Teil behandelt. Dieses Ereignis wird ausgelöst, wenn eine Datei neu ins XML DB Repository hochgeladen wird.
  • Pre-Update wird ausgelöst, wenn eine hochgeladene Datei eine bereits vorhandene gleichen Namens überschreibt. Logischerweise braucht es in diesem Event-Handler Zugriff sowohl auf die "alte" als auch auf die "neue" Datei.
  • Pre-Delete wird ausgelöst, wenn eine Datei im XML DB Repository gelöscht wird.
  • Render übernimmt, sofern es implementiert ist, die Bereitstellung der Inhalte beim Abrufen der Datei. Hiermit lässt sich also auch etwas völlig anderes, als das im XML DB Repository gespeicherte, bereitstellen.
Zuerst solltet Ihr also die bestehende Konfiguration der Event-Handler löschen. Event-Handler "hängen" an den Ordnern und Dateien des XML DB Repository. Das Neu-Konfigurieren der Event-Handler ist de-facto also ein Update auf besagten Ordnern und Dateien. Damit dieses Update nicht wiederum ein Event auslöst, empfiehlt es sich, die XML DB Events für die Session, mit der man am Event-Handler arbeitet, während dieser Arbeit abzuschalten.
alter session set XML_DB_EVENTS = DISABLE;
Dann löscht Ihr den im ersten Teil angelegten Event-Handler.
BEGIN
  DBMS_RESCONFIG.deleteResConfig(
    '/public/uploader/files', 
    '/public/uploader/resconfig/eventhandler.xml',
    DBMS_RESCONFIG.DELETE_RECURSIVE
  );
  dbms_xdb.deleteresource(
    '/public/uploader/resconfig/eventhandler.xml', 
    dbms_xdb.delete_recursive_force
  );
END;
/
sho err
Dann wird die Package Specification des PL/SQL-Paketes neu eingespielt. Nun enthält das Package vier Prozeduren: handlePreCreate, handlePreUpdate, handlePreDelete und handleRender.
CREATE OR REPLACE PACKAGE xml_eventhandler AS
  PROCEDURE handlePreCreate (eventObject DBMS_XEVENT.XDBRepositoryEvent);
  PROCEDURE handlePreDelete (eventObject DBMS_XEVENT.XDBRepositoryEvent);
  PROCEDURE handlePreUpdate (eventObject DBMS_XEVENT.XDBRepositoryEvent);
  PROCEDURE handleRender    (eventObject DBMS_XEVENT.XDBRepositoryEvent);
END xml_eventhandler;
/
sho err
Und nun der Package Body. Der Code der zusätzlichen Prozeduren ist recht einfach verständlich: Alle drei holen zunächst den Inhalt der angesprochenen Datei im XML DB Repository, also den Primary Key der entsprechenden Zeile in FILES_TAB. handlePreUpdate macht damit dann ein SQL UPDATE, handlePreDelete macht ein SQL DELETE und handleRender liest damit die Spalte CONTENT aus und gibt diesen an den Anwender zurück (SETRENDERSTREAM).
CREATE OR REPLACE PACKAGE BODY xml_eventhandler AS
  /*
   * CREATE (INSERT) Event
   */
  PROCEDURE handlePreCreate (eventObject DBMS_XEVENT.XDBRepositoryEvent) AS
    XDBResourceObj DBMS_XDBRESOURCE.XDBResource;
    ResDisplayName VARCHAR2(100);
    ResMimeType    VARCHAR2(100);

    ContentBLOB    blob;
    ContentBlobCS  number;
    IdCreated      files_tab.id%type;
  BEGIN
    XDBResourceObj := DBMS_XEVENT.getResource(eventObject);
    ResDisplayName := DBMS_XDBRESOURCE.getDisplayName(XDBResourceObj);
    ResMimeType    := DBMS_XDBRESOURCE.getContentType(XDBResourceObj);

    ContentBLOB := dbms_xdbresource.getcontentblob(XDBResourceObj, ContentBlobCS);
    insert into files_tab (
      id, file_name, mime_type, datetime, owner, content
    ) values (
      files_seq.nextval, 
      ResDisplayName, 
      ResMimeType,
      sysdate,
      sys_context('userenv','CURRENT_USER'),
      ContentBLOB
    )
    returning id into IdCreated;

    DBMS_XDBRESOURCE.setContent(XDBResourceObj, IdCreated);
    DBMS_XDBRESOURCE.setContentType(XDBResourceObj,'text/plain');
  END handlePreCreate;

  /*
   * UPDATE Event
   */
  PROCEDURE handlePreUpdate (eventObject DBMS_XEVENT.XDBRepositoryEvent) AS
    OldXDBResourceObj DBMS_XDBRESOURCE.XDBResource;
    NewXDBResourceObj DBMS_XDBRESOURCE.XDBResource;
    ResMimeType       VARCHAR2(100);

    ContentBLOB    blob;
    ContentBlobCS  number;
    IdCreated      files_tab.id%type;
  BEGIN
    NewXDBResourceObj := DBMS_XEVENT.getResource(eventObject);
    ResMimeType       := DBMS_XDBRESOURCE.getContentType(NewXDBResourceObj);
    ContentBLOB       := DBMS_XDBRESOURCE.getContentBLOB(NewXDBResourceObj, ContentBlobCS);

    OldXDBResourceObj := DBMS_XEVENT.getOldResource(eventObject);
    IdCreated := to_number(DBMS_XDBRESOURCE.getContentVARCHAR2(OldXDBResourceObj));

    update files_tab set
      content   = ContentBLOB,
      datetime  = sysdate,
      mime_type = ResMimeType
    where id = IdCreated;

    DBMS_XDBRESOURCE.setContent(NewXDBResourceObj, IdCreated);
    DBMS_XDBRESOURCE.setContentType(NewXDBResourceObj,'text/plain');
  END handlePreUpdate;

  /*
   * DELETE Event
   */
  PROCEDURE handlePreDelete (eventObject DBMS_XEVENT.XDBRepositoryEvent) AS
    XDBResourceObj    DBMS_XDBRESOURCE.XDBResource;
    IdCreated         files_tab.id%type;
  BEGIN
    XDBResourceObj := DBMS_XEVENT.getResource(eventObject);
    IdCreated := to_number(DBMS_XDBRESOURCE.getContentVARCHAR2(XDBResourceObj));

    delete from files_tab where id = IdCreated;
  END handlePreDelete;

  /*
   * RENDER (SELECT) Event
   */
  PROCEDURE handleRender (eventObject DBMS_XEVENT.XDBRepositoryEvent) AS
    XDBResourceObj    DBMS_XDBRESOURCE.XDBResource;

    IdCreated         files_tab.id%type;
    ContentBLOB       blob;
  BEGIN
    XDBResourceObj := DBMS_XEVENT.getResource(eventObject);
    IdCreated := to_number(DBMS_XDBRESOURCE.getContentVARCHAR2(XDBResourceObj));

    select content into ContentBLOB
    from files_tab
    where id = IdCreated;

    DBMS_XEVENT.setRenderStream(eventObject, ContentBLOB);
  END handleRender;
end xml_eventhandler;
/
sho err
Nun könnt die die XML DB Repository Event-Handler neu registrieren ...
DECLARE
  b BOOLEAN := FALSE;
BEGIN
  b := DBMS_XDB.createResource(
    '/public/uploader/resconfig/eventhandler.xml',
    '<ResConfig xmlns="http://xmlns.oracle.com/xdb/XDBResConfig.xsd"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://xmlns.oracle.com/xdb/XDBResConfig.xsd
                                    http://xmlns.oracle.com/xdb/XDBResConfig.xsd">
       <event-listeners>
         <listener>
           <description>Category application</description>
           <schema>' || sys_context('userenv','CURRENT_SCHEMA') || '</schema>
           <source>XML_EVENTHANDLER</source>
           <language>PL/SQL</language>
           <events>
             <Pre-Create/>
             <Pre-Update/>
             <Pre-Delete/>
             <Render/>
           </events>
         </listener>
       </event-listeners>
       <defaultChildConfig>
         <configuration>
           <path>/public/uploader/resconfig/eventhandler.xml</path>
         </configuration>
       </defaultChildConfig>
     </ResConfig>',
    'http://xmlns.oracle.com/xdb/XDBResConfig.xsd',
    'ResConfig'
  );
END;
/

BEGIN
  DBMS_RESCONFIG.appendResConfig(
    '/public/uploader/files', 
    '/public/uploader/resconfig/eventhandler.xml',
    DBMS_RESCONFIG.APPEND_RECURSIVE
  );
END;
/
sho err

commit
/
Zum Abschluss müssen die XML DB Events wieder aktiviert werden.
alter session set XML_DB_EVENTS = ENABLE;
Und das war's auch schon. Wenn Ihr nun per FTP Dateien hochladet, aktualisiert oder löscht, werdet Ihr feststellen, dass sich die Tabelle FILES_TAB komplett analog dazu verhält. Und wenn Ihr die Dateien wieder herunterladet, wird tatsächlich der Inhalt aus der Tabelle FILES_TAB bereitgestellt. Wir haben eine FTP-Schnittstelle für eine Tabelle implementiert - mit nichts als der Datenbank. Zuerst also einige Dateien (per FTP) hochladen ...
ftp> open sccloud033 2100
Connected to sccloud033.de.oracle.com.
220- sccloud033.de.oracle.com
Unauthorised use of this FTP server is prohibited and may be subject to civil and criminal prosecution.
220 sccloud033.de.oracle.com FTP Server (Oracle XML DB/Oracle Database) ready.
ftp> user testit oracle
331 pass required for TESTIT
230 TESTIT logged in
ftp> cd /public/uploader/files
250 CWD Command successful
ftp> bin
200  Type set to I.
ftp> prom
Interactive mode Off .
ftp> mput *
200 PORT Command successful
150 BIN Data Connection
226 BIN Transfer Complete
ftp: 1935722 bytes sent in 0,22Seconds 8680,37Kbytes/sec.
:
ftp> dir
200 PORT Command successful
150 ASCII Data Connection
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild01.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild02.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild03.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild04.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild05.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild06.jpg
... in der Tabelle sieht das dann so aus.
SQL> select file_name, mime_type, dbms_lob.getlength(content) fsize from files_tab;

FILE_NAME       MIME_TYPE                 FSIZE
--------------- -------------------- ----------
Bild01.jpg      image/jpeg              1935722
Bild02.jpg      image/jpeg              3483872
Bild03.jpg      image/jpeg              2300657
Bild04.jpg      image/jpeg              3003526
Bild05.jpg      image/jpeg              2245385
Bild06.jpg      image/jpeg              2350616
Dann eine Datei löschen ...
ftp> del Bild01.jpg
250 DELE Command successful
ftp> dir
200 PORT Command successful
150 ASCII Data Connection
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild02.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild03.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild04.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild05.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild06.jpg
... was sich in der Tabelle ebenfalls sofort wiederfindet.
SQL> select file_name, mime_type, dbms_lob.getlength(content) fsize from files_tab;

FILE_NAME       MIME_TYPE                 FSIZE
--------------- -------------------- ----------
Bild02.jpg      image/jpeg              3483872
Bild03.jpg      image/jpeg              2300657
Bild04.jpg      image/jpeg              3003526
Bild05.jpg      image/jpeg              2245385
Bild06.jpg      image/jpeg              2350616
Viel Spaß damit. Natürlich lässt sich das ganze nun nochmals viel weiter treiben. So wäre es eine Möglichkeit, die Zeile der Tabelle FILES_TAB im DELETE-Handler nicht einfach zu löschen, sondern diese in eine andere (Archiv-)Tabelle zu überführen. Ein Loggings ließe sich sehr einfach programmieren - es gibt kaum Grenzen.
Zum Abschluß möchte ich euch die Dokumentation zu den XML DB Repository Events nicht vorenthalten: Ihr findet Sie in Kapitel 30 des XML DB Developers' Guide.
Here is the second part of the blog posting about FTP'ing files into your own tables with the Oracle Database and the XML DB repository. In the first part is introduced Oracle XML DB protocol servers, the repository and Repository Events. We also implemented a simple example, which redirects uploaded files into a particular table, FILES_TAB. After this, the file within the XML DB repository just contains a primary key value for the FILES_TAB table - the file content is stored in the very row this PK value is pointing to. Today we're going to make this example complete: We want to handle also Change, Delete and Download events - all these should work on the FILES_TAB table instead of the XML DB repository.
  • Pre-Create has been implemented in the first part. This event fires, when a new file is being uploaded to the XML DB repository..
  • Pre-Update fires, when an uploaded file overwrites an existing one with the same name. Consequently, within this event, we need access to both the "old" and "new" file contents.
  • Pre-Delete fires, when a file in the XML DB repository is being deleted.
  • Render comes to action, when file contents are being downloaded from the XML DB repository. The code of this event handler determines the actual file contents transmitted to the client.
Before proceeding, we should delete the existing event handler configuration from the first blog posting. But wait: All event handlers are part of the metadata of a XML DB resource. So changing the event handler configuration changes the resource itself - so it fires -again- an update event. To prevent the firing on unwanted events (and therefore unwanted actions from PL/SQL event handlers), it's advisable to disable XML DB events for the database session you are working with.
alter session set XML_DB_EVENTS = DISABLE;
Now, delete the existing event handlers.
BEGIN
  DBMS_RESCONFIG.deleteResConfig(
    '/public/uploader/files', 
    '/public/uploader/resconfig/eventhandler.xml',
    DBMS_RESCONFIG.DELETE_RECURSIVE
  );
  dbms_xdb.deleteresource(
    '/public/uploader/resconfig/eventhandler.xml', 
    dbms_xdb.delete_recursive_force
  );
END;
/
sho err
Then, replace the existing Package Specification for your event handler package with the following one. This one contains not one, but four handler procedures: handlePreCreate, handlePreUpdate, handlePreDelete und handleRender.
CREATE OR REPLACE PACKAGE xml_eventhandler AS
  PROCEDURE handlePreCreate (eventObject DBMS_XEVENT.XDBRepositoryEvent);
  PROCEDURE handlePreDelete (eventObject DBMS_XEVENT.XDBRepositoryEvent);
  PROCEDURE handlePreUpdate (eventObject DBMS_XEVENT.XDBRepositoryEvent);
  PROCEDURE handleRender    (eventObject DBMS_XEVENT.XDBRepositoryEvent);
END xml_eventhandler;
/
sho err
After that, install the Package Body. The code of the new procedures is rather simple: All of them first look into the contents of the existing repository file (you remember: it contains the primary key value for the row in FILES_TAB). handlePreUpdate then performs a SQL UPDATE action, handlePreDelete does SQL DELETE and handleRender reads the CONTENT column into a BLOB variable and passes this to SETRENDERSTREAM - this leads to the BLOB content being passed to the client.
CREATE OR REPLACE PACKAGE BODY xml_eventhandler AS
  /*
   * CREATE (INSERT) Event
   */
  PROCEDURE handlePreCreate (eventObject DBMS_XEVENT.XDBRepositoryEvent) AS
    XDBResourceObj DBMS_XDBRESOURCE.XDBResource;
    ResDisplayName VARCHAR2(100);
    ResMimeType    VARCHAR2(100);

    ContentBLOB    blob;
    ContentBlobCS  number;
    IdCreated      files_tab.id%type;
  BEGIN
    XDBResourceObj := DBMS_XEVENT.getResource(eventObject);
    ResDisplayName := DBMS_XDBRESOURCE.getDisplayName(XDBResourceObj);
    ResMimeType    := DBMS_XDBRESOURCE.getContentType(XDBResourceObj);

    ContentBLOB := dbms_xdbresource.getcontentblob(XDBResourceObj, ContentBlobCS);
    insert into files_tab (
      id, file_name, mime_type, datetime, owner, content
    ) values (
      files_seq.nextval, 
      ResDisplayName, 
      ResMimeType,
      sysdate,
      sys_context('userenv','CURRENT_USER'),
      ContentBLOB
    )
    returning id into IdCreated;

    DBMS_XDBRESOURCE.setContent(XDBResourceObj, IdCreated);
    DBMS_XDBRESOURCE.setContentType(XDBResourceObj,'text/plain');
  END handlePreCreate;

  /*
   * UPDATE Event
   */
  PROCEDURE handlePreUpdate (eventObject DBMS_XEVENT.XDBRepositoryEvent) AS
    OldXDBResourceObj DBMS_XDBRESOURCE.XDBResource;
    NewXDBResourceObj DBMS_XDBRESOURCE.XDBResource;
    ResMimeType       VARCHAR2(100);

    ContentBLOB    blob;
    ContentBlobCS  number;
    IdCreated      files_tab.id%type;
  BEGIN
    NewXDBResourceObj := DBMS_XEVENT.getResource(eventObject);
    ResMimeType       := DBMS_XDBRESOURCE.getContentType(NewXDBResourceObj);
    ContentBLOB       := DBMS_XDBRESOURCE.getContentBLOB(NewXDBResourceObj, ContentBlobCS);

    OldXDBResourceObj := DBMS_XEVENT.getOldResource(eventObject);
    IdCreated := to_number(DBMS_XDBRESOURCE.getContentVARCHAR2(OldXDBResourceObj));

    update files_tab set
      content   = ContentBLOB,
      datetime  = sysdate,
      mime_type = ResMimeType
    where id = IdCreated;

    DBMS_XDBRESOURCE.setContent(NewXDBResourceObj, IdCreated);
    DBMS_XDBRESOURCE.setContentType(NewXDBResourceObj,'text/plain');
  END handlePreUpdate;

  /*
   * DELETE Event
   */
  PROCEDURE handlePreDelete (eventObject DBMS_XEVENT.XDBRepositoryEvent) AS
    XDBResourceObj    DBMS_XDBRESOURCE.XDBResource;
    IdCreated         files_tab.id%type;
  BEGIN
    XDBResourceObj := DBMS_XEVENT.getResource(eventObject);
    IdCreated := to_number(DBMS_XDBRESOURCE.getContentVARCHAR2(XDBResourceObj));

    delete from files_tab where id = IdCreated;
  END handlePreDelete;

  /*
   * RENDER (SELECT) Event
   */
  PROCEDURE handleRender (eventObject DBMS_XEVENT.XDBRepositoryEvent) AS
    XDBResourceObj    DBMS_XDBRESOURCE.XDBResource;

    IdCreated         files_tab.id%type;
    ContentBLOB       blob;
  BEGIN
    XDBResourceObj := DBMS_XEVENT.getResource(eventObject);
    IdCreated := to_number(DBMS_XDBRESOURCE.getContentVARCHAR2(XDBResourceObj));

    select content into ContentBLOB
    from files_tab
    where id = IdCreated;

    DBMS_XEVENT.setRenderStream(eventObject, ContentBLOB);
  END handleRender;
end xml_eventhandler;
/
sho err
Now re-register the event handlers. Note that the XML document describing these must also be adjusted.
DECLARE
  b BOOLEAN := FALSE;
BEGIN
  b := DBMS_XDB.createResource(
    '/public/uploader/resconfig/eventhandler.xml',
    '<ResConfig xmlns="http://xmlns.oracle.com/xdb/XDBResConfig.xsd"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://xmlns.oracle.com/xdb/XDBResConfig.xsd
                                    http://xmlns.oracle.com/xdb/XDBResConfig.xsd">
       <event-listeners>
         <listener>
           <description>Category application</description>
           <schema>' || sys_context('userenv','CURRENT_SCHEMA') || '</schema>
           <source>XML_EVENTHANDLER</source>
           <language>PL/SQL</language>
           <events>
             <Pre-Create/>
             <Pre-Update/>
             <Pre-Delete/>
             <Render/>
           </events>
         </listener>
       </event-listeners>
       <defaultChildConfig>
         <configuration>
           <path>/public/uploader/resconfig/eventhandler.xml</path>
         </configuration>
       </defaultChildConfig>
     </ResConfig>',
    'http://xmlns.oracle.com/xdb/XDBResConfig.xsd',
    'ResConfig'
  );
END;
/

BEGIN
  DBMS_RESCONFIG.appendResConfig(
    '/public/uploader/files', 
    '/public/uploader/resconfig/eventhandler.xml',
    DBMS_RESCONFIG.APPEND_RECURSIVE
  );
END;
/
sho err

commit
/
Finally re-enable XML DB events within your database session.
alter session set XML_DB_EVENTS = ENABLE;
And then you are finished. Upon uploading, replacing or deleting files with FTP, wou'll notice that your database performs corresponding actions on your FILES_TAB table. Downloading a file using FTP leads to the contents of FILES_TAB being actually passed to the client. You have a complete FTP interface for your table. Try it out. First, upload some files via FTP.
ftp> open sccloud033 2100
Connected to sccloud033.de.oracle.com.
220- sccloud033.de.oracle.com
Unauthorised use of this FTP server is prohibited and may be subject to civil and criminal prosecution.
220 sccloud033.de.oracle.com FTP Server (Oracle XML DB/Oracle Database) ready.
ftp> user testit oracle
331 pass required for TESTIT
230 TESTIT logged in
ftp> cd /public/uploader/files
250 CWD Command successful
ftp> bin
200  Type set to I.
ftp> prom
Interactive mode Off .
ftp> mput *
200 PORT Command successful
150 BIN Data Connection
226 BIN Transfer Complete
ftp: 1935722 bytes sent in 0,22Seconds 8680,37Kbytes/sec.
:
ftp> dir
200 PORT Command successful
150 ASCII Data Connection
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild01.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild02.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild03.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild04.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild05.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild06.jpg
... your table will then look similar to this ...
SQL> select file_name, mime_type, dbms_lob.getlength(content) fsize from files_tab;

FILE_NAME       MIME_TYPE                 FSIZE
--------------- -------------------- ----------
Bild01.jpg      image/jpeg              1935722
Bild02.jpg      image/jpeg              3483872
Bild03.jpg      image/jpeg              2300657
Bild04.jpg      image/jpeg              3003526
Bild05.jpg      image/jpeg              2245385
Bild06.jpg      image/jpeg              2350616
Deleting a file ...
ftp> del Bild01.jpg
250 DELE Command successful
ftp> dir
200 PORT Command successful
150 ASCII Data Connection
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild02.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild03.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild04.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild05.jpg
-rw-r--r--   1 TESTIT   oracle         1 MAY 26 11:44 Bild06.jpg
... leads to a deletion within the table.
SQL> select file_name, mime_type, dbms_lob.getlength(content) fsize from files_tab;

FILE_NAME       MIME_TYPE                 FSIZE
--------------- -------------------- ----------
Bild02.jpg      image/jpeg              3483872
Bild03.jpg      image/jpeg              2300657
Bild04.jpg      image/jpeg              3003526
Bild05.jpg      image/jpeg              2245385
Bild06.jpg      image/jpeg              2350616
And of course, this simple scenario could be extended. You can easily have a logging facility, you could handle a DELETE event differently; that means: not deleting the FILES_TAB row, but actually copying it to an archive table. And many more ...
And the last word: The documentation on XML DB repository events is contained in chapter 30 of XML DB Developers' Guide.

Beliebte Postings