Solucionar problema con funciones JAVA en Oracle 12.2 "DirList" (An exception has occurred in the compiler (1.8.0_181))

Hola Amig@s,

Si recientemente hemos actualizado la version de Oracle a una 12.2 o superior, nos encontraremos con un problema. A partir de la 12.2 Oracle ya no soporta ejecuciones SQLJ.

https://docs.oracle.com/en/database/oracle/oracle-database/18/jsqlj/changes-this-release-oracle-sqlj-developers-guide.html

Desupported Features
The following features are no longer supported by Oracle:
SQLJ in the Server
Starting with Oracle Database 12c Release 2 (12.2), Oracle does not support server-side SQLJ code.
Oracle supports using client-side SQLJ. However, Oracle does not support the use of server-side SQLJ, including running stored procedures, functions, and triggers in the database environment.

Esto es un gran problema si por ejemplo, utilizamos funciones para leer ficheros locales desde un procedimiento. Existe un procedimiento de lectura de ficheros muy común entre los DBA que nos permite leer ficheros locales a partir de pasarle como parámetro el directorio y el patrón de búsqueda (wildcard).

La famosa función se llama DIRLIST pero cuando cuando la ejecutamos en una Oracle 12.2 nos mostrará el siguiente mensaje:

Errors for JAVA SOURCE "DirList":

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0      An exception has occurred in the compiler (1.8.0_181). Please
         file a bug against the Java compiler via the Java bug reporting
         page (http://bugreport.java.com) after checking the Bug Database
         (http://bugs.java.com) for duplicates. Include your program and
         the following diagnostic in your report. Thank you.

0/0      at oracle.aurora.rdbms.Compiler.compile(Compiler.java:317)
0/0      at
         com.sun.tools.javac.util.JCDiagnostic.<init>(JCDiagnostic.java:41
         2)

Esto se debe a lo que comentaba, a partir de la version 12.2 Oracle no permite ejecuciones SQLJ del lado del servidor de BBDD.

Un código de ejemplo de DirList que funciona en versiones <12.1 es el siguiente:

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED MOSTRARFICHEROS as import java.io.*;
    import java.sql.*;

    public class DirList {

        public static void lista(String directory)
         throws SQLException  {

             File[] files = new File(directory).listFiles();
             java.lang.String element;

            for (File file : files) {
                if (file.isFile()) {
                    element = file.getName();
                    #sql {INSERT INTO DIR_LIST (x) VALUES (:element)};
                }
            }
         };

    }
/

Ahora bien, con una pequeña modificación podemos hacerlo compatible con 12.2 de la siguiente manera:

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED MOSTRARFICHEROS  as
    import java.io.*;
    import java.sql.*;
    public class DirList {
    public static void lista(String directory)
    throws SQLException {
           Connection conn = DriverManager.getConnection("jdbc:default:connection:");
           String sql = "INSERT INTO DIR_LIST (x) VALUES (?)";

           File path = new File(directory);
          String[] list = path.list();
          String element;

          for (int i = 0; i < list.length; i++) {
                 element = list[i];

                 PreparedStatement pstmt = conn.prepareStatement(sql);
                 pstmt.setString(1, element);

                 pstmt.executeUpdate();
                 pstmt.close();
          }
          }
   }
   /

Tendremos que crear un procedimiento para cargarlo en una lista:
 
create or replace procedure
     MOSTRAR_FICHEROS( DIRECTORIO in varchar2)
    as language java
    name 'DirList.lista(java.lang.String)';
    /

Hay que asignar los permisos pertinentes (actualizar el usuario de bbdd):

DECLARE
 KEYNUM NUMBER;
BEGIN
  SYS.DBMS_JAVA.GRANT_PERMISSION(
     grantee           => 'USUARIOBBDD'
    ,permission_type   => 'SYS:java.io.FilePermission'
    ,permission_name   => '<<ALL FILES>>'
    ,permission_action => 'read ,write, execute, delete'
    ,key               => KEYNUM
    );
END;
/

Luego para probarlo simplemente podemos ejecutar:

SQL> exec MOSTRAR_FICHEROS('/home/oracle');
PL/SQL procedure successfully completed.
SQL> select * from MOSTRARFICHEROS where rownum <=3;
X
------------------------------
1.TXT
2.TXT
Share on Google Plus
    Blogger Comment

0 comentarios: