views:

62

answers:

1

Hi guys, I've been stuck with this for past two days. I've go java function stored in Oracle system which is supposed to copy image from local drive do remote database and store it in BLOB - it's called CopyBLOB and looks like this:

  import java.sql.*;  
  import oracle.sql.*;
  import java.io.*;

public class CopyBLOB 
{
  static int id;
  static String  fileName = null;
  static Connection conn = null;  

  public CopyBLOB(int idz, String f) 
  {
    id       = idz;
    fileName   = f;
  }

   public static void copy(int ident, String path) throws SQLException, FileNotFoundException 
   {
       CopyBLOB cpB = new CopyBLOB(ident, path);
       cpB.getConnection();
       cpB.callUpdate(id, fileName);
   }

    public void getConnection() throws SQLException
    {    
     DriverManager.registerDriver (new oracle.jdbc.OracleDriver());
     try 
     {     
       conn = DriverManager.getConnection("jdbc:oracle:thin:@oraserv.ms.mff.cuni.cz:1521:db", "xxx", "xxx");
     } 
     catch (SQLException sqlex) 
     {
         System.out.println("SQLException while getting db connection: "+sqlex);
         if (conn != null)  conn.close();
     } 
     catch (Exception ex) 
     {
         System.out.println("Exception while getting db connection: "+ex);
         if (conn != null) conn.close();
     }
    }

    public void callUpdate(int id, String file ) throws SQLException, FileNotFoundException 
    {
      CallableStatement cs = null;
      try 
      {  
        conn.setAutoCommit(false);
        File f = new File(file);
        FileInputStream fin = new FileInputStream(f);
        cs = (CallableStatement) conn.prepareCall( "begin add_image(?,?); end;" );
        cs.setInt(1, id );
        cs.setBinaryStream(2, fin, (int) f.length());
        cs.execute();
        conn.setAutoCommit(true);        
      } 
      catch ( SQLException sqlex ) 
      {
            System.out.println("SQLException in callUpdateUsingStream method of given status : " + sqlex.getMessage() );
      } 
      catch ( FileNotFoundException fnex ) 
      {
            System.out.println("FileNotFoundException in callUpdateUsingStream method of given status : " + fnex.getMessage() );
      } 
      finally 
      {
          try 
          {          
            if (cs != null)  cs.close();
            if (conn != null) conn.close();
          } 
          catch ( Exception ex ) 
          {
            System.out.println("Some exception in callUpdateUsingStream method of given status : " + ex.getMessage(  ) );
          }
      }
    }
}

The wrapper function is defined in package "MyPackage" as folows:

  procedure image_adder( id varchar2, path varchar2 )  
  AS
    language java name 'CopyBLOB.copy(java.lang.String, java.lang.String)';

And the inserting function called image_add is as simple as this:

procedure add_image( id numeric(10), pic blob)
  AS 

  BEGIN
    insert into pictures values (seq_pic.nextval, id, pic);
  END add_image;

Now the problem: When I type

call MyPackage.image_adder(1, 'd:\samples\img.jpg');

I get the ORA-29531 Error: No method copy in class CopyBLOB. Can you help me, please?

+1  A: 

The method in your class has this signature:

public static void copy(int ident, String path)

But in your Java Stored Procedure you have specified this signature:

'CopyBLOB.copy(java.lang.String, java.lang.String)'

I think if you change the first argument to java,lang.Integer your problem should resolve itself. You should probably change the datatype of the ID parameter in the IMAGE_ADDER() procedure as well.

edit

"Any ideas how to upload local files?"

Not unreasonably, the database can only interact with files which are visible to its server. Generally that limits matters to files and directories which are physically on the same box, unless the network admin has mapped some remote drives.

Transferring files from a local PC drive to a server is really a client i.e. application issue, it isn't the sort of thing the database should really get involved with.

I know that isn't what you were hoping to hear. If you really want to drive the file uploading from teh database, then the mechanism remains the same whenever we want to transfer files across a network: FTP. Tim Hall has published a PL/SQL implementation for FTP on his Oracle-Base site. Find out more.

"long as the file is smaler than 2000B (WTF?)"

That is suspiciously close to the BINARY CHAR limit (2000). In older versions of Oracle we had to use a two-step process: insert a placeholder and then issue an update. Something like this:

  procedure add_image( id numeric(10), pic blob) 
  AS       
  BEGIN 
      insert into pictures 
          values (seq_pic.nextval, id, empty_blob()); 
      update pictures 
      set col_pic = pic
      where id = seq_pic.currval;
  END add_image;
APC
You're right - it was kind of left over from previous work and I didn't notice it. Thank you for that, but there is another problem: add_image procedure is not run. I have no idea why, Oracle says that transaction succeded, but nothing happens. Any ideas? Thanks.
@mumich - how do you know it isn't being run? Also, why are you unsetting and then setting AutoCommit mode? The execute() happens while AutoCommit is off. As you have no explicit commit, is it possible that the insert is run but isn't saved?
APC
The rason why it wasn't run is the procedure exited b4 that with FileNotFoundException. That means problem solved but it's another thing I don't get. The source is from Internet and I expected I could provide it with path to the local file eg. d:\pic.jpg and that the class would create connection and upload the file to the server. This doesn't happen. When I provide it wits a server path eg. /home/pic.jpg it works (as long as the file is smaler than 2000B (WTF?)). I run everything under SQL Developer. Any ideas how to upload local files? Thanks a lot for your time and help.