Discussion:
Zipping multiple BLOBs
(too old to reply)
cdefelice
2010-02-18 22:37:30 UTC
Permalink
Hello,

First of all, I have virtually no experience with Java but I've been
tasked with putting this thing together and I've finally hit a dead
end. Basically, what I am creating is a PL/SQL (Oracle 10g) web form
so that clients may download specific files stored as BLOBs from the
database. This is fine and dandy if they want to download one file at
a time. What I need to do is come up with a way to pull multiple BLOB
files, zip them up in one big BLOB, and serve it as a download. Since
this cannot be done in PL/SQL alone, I turned to Java.

So far I have not been able to find one successful example of how to
do this. What I have so far produces a zip file with only the first of
the selected BLOBs inside of it. I am basically just looping through
the list of selected BLOBs while passing each selected BLOB to the
Java procedure as well as the zip BLOB but it doesn't seem to be
appending anything to the zipped BLOB after the first iteration. Here
is the code:

public static void zipBlob(oracle.sql.BLOB srcBlob, oracle.sql.BLOB
dstBlob[],java.lang.String name)
{
try
{
Connection conn =
DriverManager.getConnection("jdbc:default:connection:");

OutputStream outBuffer = dstBlob[0].setBinaryStream(0);
InputStream inBuffer = srcBlob.getBinaryStream();
ZipOutputStream zip = new ZipOutputStream(outBuffer);
zip.setMethod(ZipOutputStream.DEFLATED);
byte[] tmpBuffer = new byte[1024];
ZipEntry entry = new ZipEntry(name);
zip.putNextEntry(entry);
int n;

while ((n = inBuffer.read(tmpBuffer)) >= 0)
{
zip.write(tmpBuffer, 0, n);
}

zip.close();
}
catch (SQLException e)
{
System.err.println(e);
}
catch (IOException e)
{
System.err.println(e);
}
}

I appreciate any examples or pointers as to why this is not working.
Thanks
Ian Shef
2010-02-18 23:14:09 UTC
Permalink
Post by cdefelice
Hello,
First of all, I have virtually no experience with Java but I've been
tasked with putting this thing together and I've finally hit a dead
end. Basically, what I am creating is a PL/SQL (Oracle 10g) web form
so that clients may download specific files stored as BLOBs from the
database. This is fine and dandy if they want to download one file at
a time. What I need to do is come up with a way to pull multiple BLOB
files, zip them up in one big BLOB, and serve it as a download. Since
this cannot be done in PL/SQL alone, I turned to Java.
So far I have not been able to find one successful example of how to
do this. What I have so far produces a zip file with only the first of
the selected BLOBs inside of it. I am basically just looping through
the list of selected BLOBs while passing each selected BLOB to the
Java procedure as well as the zip BLOB but it doesn't seem to be
appending anything to the zipped BLOB after the first iteration. Here
I admit that I don't know SQL, don't know BLOBs, and haven't worked with
zip files from Java, but I am going to take a shot at this anyway.
Post by cdefelice
public static void zipBlob(oracle.sql.BLOB srcBlob,
oracle.sql.BLOB
dstBlob[],java.lang.String name)
String should be sufficient, java.lang.String is overkill. java.lang.* is
automatically imported by the compiler without any action on your part.
This is not an error, it just looks peculiar.
Post by cdefelice
{
try
{
Connection conn =
DriverManager.getConnection("jdbc:default:connection:");
OutputStream outBuffer =
dstBlob[0].setBinaryStream(0);
I see dstBlob[0] but I don't see any loop to get any other BLOBs. I also
don't see any protection against the possibility that there is no 0
element.
Post by cdefelice
InputStream inBuffer = srcBlob.getBinaryStream();
ZipOutputStream zip = new
ZipOutputStream(outBuffer);
zip.setMethod(ZipOutputStream.DEFLATED);
byte[] tmpBuffer = new byte[1024];
ZipEntry entry = new ZipEntry(name);
What are you going to use for the name of any additional entries, once you
put a loop in to handle more entries?
Post by cdefelice
zip.putNextEntry(entry);
int n;
while ((n = inBuffer.read(tmpBuffer)) >= 0)
{
zip.write(tmpBuffer, 0, n);
}
zip.close();
}
catch (SQLException e)
{
System.err.println(e);
}
catch (IOException e)
{
System.err.println(e);
}
}
I appreciate any examples or pointers as to why this is not working.
Thanks
I hope this helps. Good luck!
cdef
2010-02-19 13:53:37 UTC
Permalink
Post by Ian Shef
Post by cdefelice
Hello,
First of all, I have virtually no experience with Java but I've been
tasked with putting this thing together and I've finally hit a dead
end. Basically, what I am creating is a PL/SQL (Oracle 10g) web form
so that clients may download specific files stored as BLOBs from the
database. This is fine and dandy if they want to download one file at
a time. What I need to do is come up with a way to pull multiple BLOB
files, zip them up in one big BLOB, and serve it as a download. Since
this cannot be done in PL/SQL alone, I turned to Java.
So far I have not been able to find one successful example of how to
do this. What I have so far produces a zip file with only the first of
the selected BLOBs inside of it. I am basically just looping through
the list of selected BLOBs while passing each selected BLOB to the
Java procedure as well as the zip BLOB but it doesn't seem to be
appending anything to the zipped BLOB after the first iteration. Here
I admit that I don't know SQL, don't know BLOBs, and haven't worked with
zip files from Java, but I am going to take a shot at this anyway.
Post by cdefelice
          public static void zipBlob(oracle.sql.BLOB srcBlob,
          oracle.sql.BLOB
dstBlob[],java.lang.String name)
String should be sufficient, java.lang.String is overkill.  java.lang.* is
automatically imported by the compiler without any action on your part.  
This is not an error, it just looks peculiar.
Post by cdefelice
          {
               try
               {
                    Connection conn =
DriverManager.getConnection("jdbc:default:connection:");
                    OutputStream outBuffer =
                    dstBlob[0].setBinaryStream(0);
I see dstBlob[0] but I don't see any loop to get any other BLOBs.  I also
don't see any protection against the possibility that there is no 0
element.
Post by cdefelice
                    InputStream inBuffer = srcBlob.getBinaryStream();
                    ZipOutputStream zip = new
                    ZipOutputStream(outBuffer);
                    zip.setMethod(ZipOutputStream.DEFLATED);
                    byte[] tmpBuffer = new byte[1024];
                    ZipEntry entry = new ZipEntry(name);
What are you going to use for the name of any additional entries, once you
put a loop in to handle more entries?
Post by cdefelice
                    zip.putNextEntry(entry);
                    int n;
                    while ((n = inBuffer.read(tmpBuffer)) >= 0)
                    {
                         zip.write(tmpBuffer, 0, n);
                    }
                    zip.close();
               }
               catch (SQLException e)
               {
                    System.err.println(e);
               }
               catch (IOException e)
               {
                    System.err.println(e);
               }
          }
I appreciate any examples or pointers as to why this is not working.
Thanks
I hope this helps.  Good luck!
First and foremost, thank you for replying. I really appreciate it.

In PL/SQL I am looping through the list of selected BLOB files and
calling the Java procedure, each time passing it a new BLOB source
file, the file name of that specific BLOB source, and the same BLOB
destination (zip) file. I'm just trying to pass the Java procedure one
new file at a time and append it to the zip file. I see what you mean
about looping through the destination BLOB array. My understanding,
and correct me if I'm wrong, is that each time the Java procedure is
called I should be able to determine the array count of the
destination BLOB and pick up at the end and append more zip entries. I
have tried to do exactly this with something like "int z_length =
dstBlob.length();" or "int z_length = getLength(dstBlob);". My problem
is that I don't know 1) which one returns the array count vs the BLOB
size 2) how to use the z_length value once I've obtained it. If I try
"dstBlob[z_length].setBinaryStream(0);" I get a
java.lang.ArrayIndexOutOfBoundsException exception.
John B. Matthews
2010-02-19 18:10:33 UTC
Permalink
In article
Post by cdef
In PL/SQL I am looping through the list of selected BLOB files and
calling the Java procedure, each time passing it a new BLOB source
file, the file name of that specific BLOB source, and the same BLOB
destination (zip) file. I'm just trying to pass the Java procedure
one new file at a time and append it to the zip file. I see what you
mean about looping through the destination BLOB array. My
understanding, and correct me if I'm wrong, is that each time the
Java procedure is called I should be able to determine the array
count of the destination BLOB and pick up at the end and append more
zip entries. I have tried to do exactly this with something like "int
z_length = dstBlob.length();" or "int z_length =
getLength(dstBlob);". My problem is that I don't know 1) which one
returns the array count vs the BLOB size 2) how to use the z_length
value once I've obtained it. If I try
"dstBlob[z_length].setBinaryStream(0);" I get a
java.lang.ArrayIndexOutOfBoundsException exception.
IIUC, you can't append a ZipEntry to an existing archive without reading
the old file and creating a new one. You could try passing a list of
BLOBs to the Java side and compress them all at once.

I understand you're on 10g, but I see an 11g solution using
JDBMS_COMPRESS that may lead somewhere:

<http://forums.oracle.com/forums/thread.jspa?threadID=835022>
<http://oracle-jutils.sourceforge.net/>
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
Lew
2010-02-19 18:22:50 UTC
Permalink
Post by cdef
and correct me if I'm wrong, is that each time the Java procedure is
called I should be able to determine the array count of the
destination BLOB and pick up at the end and append more zip entries. I
have tried to do exactly this with something like "int z_length =
dstBlob.length();" or "int z_length = getLength(dstBlob);". My problem
is that I don't know 1) which one returns the array count vs the BLOB
size 2) how to use the z_length value once I've obtained it. If I try
"dstBlob[z_length].setBinaryStream(0);" I get a
java.lang.ArrayIndexOutOfBoundsException exception.
Before getting to your question, let me suggest strongly that you please do
not use TABs to indent Usenet listings. Using a maximum of four space
characters per indent level to keep your listings readable.

Now to your question. First, why do you use 'oracle.sql.BLOB' and not a
standard type?
Post by cdef
public static void zipBlob(
oracle.sql.BLOB srcBlob, oracle.sql.BLOB dstBlob[], String name )
Second, don't give code examples as "something like ...". Give copied and
pasted *exact* code that you tried, as an SSCCE.
<http://sscce.com/>

Third, the "something like ..." code you describe won't compile. Arrays in
Java do not have a 'length()' method, and you don't show the 'getLength( BLOB
)' method to which you refer, so I can't speak to that. Arrays in Java have a
'length' attribute, thus 'someArray.length'. This is very basic Java.

Fourth, the "something like ..." code you describe will throw an
'ArrayIndexOutOfBoundsException' once you fix the compilation problems, as
you've seen. Assuming you set 'z_length' (a name that violates the Java
coding conventions, which call for camel case and no underscores in
non-constant variable names) from the array 'length' attribute, it cannot be
used as an array index for the same array. Arrays in Java do not change size,
and the maximum index of an array is one less than its length. Trying to
reference array element 'zLength' (to correct your name) uses an index that is
out of bounds.

Fifth, if you want to add to an array, you need to create a longer array and
copy the 'zLength' elements of the old array into the first 'zLength' elements
of the new array. Make sure the new array is long enough to handle all the
new elements you want to add (maximum index "length minus one").

For a self-growing array-like structure use a 'java.util.List' instead of an
array. The 'java.util.ArrayList' is closest to a regular array and simplest
of the 'List' implementations.

Have you read the Java tutorials on java.sun.com? If not, you must. They
contain answers to some of the questions you asked.
--
Lew
cdef
2010-02-19 21:06:11 UTC
Permalink
Post by Lew
Post by cdef
and correct me if I'm wrong, is that each time the Java procedure is
called I should be able to determine the array count of the
destination BLOB and pick up at the end and append more zip entries. I
have tried to do exactly this with something like "int z_length =
dstBlob.length();" or "int z_length = getLength(dstBlob);". My problem
is that I don't know 1) which one returns the array count vs the BLOB
size 2) how to use the z_length value once I've obtained it. If I try
"dstBlob[z_length].setBinaryStream(0);" I get a
java.lang.ArrayIndexOutOfBoundsException exception.
Before getting to your question, let me suggest strongly that you please do
not use TABs to indent Usenet listings.  Using a maximum of four space
characters per indent level to keep your listings readable.
Now to your question.  First, why do you use 'oracle.sql.BLOB' and not a
standard type?
Post by cdef
public static void zipBlob(
  oracle.sql.BLOB srcBlob, oracle.sql.BLOB dstBlob[], String name )
Second, don't give code examples as "something like ...".  Give copied and
pasted *exact* code that you tried, as an SSCCE.
<http://sscce.com/>
Third, the "something like ..." code you describe won't compile.  Arrays in
Java do not have a 'length()' method, and you don't show the 'getLength( BLOB
)' method to which you refer, so I can't speak to that.  Arrays in Java have a
'length' attribute, thus 'someArray.length'.  This is very basic Java.
Fourth, the "something like ..." code you describe will throw an
'ArrayIndexOutOfBoundsException' once you fix the compilation problems, as
you've seen.  Assuming you set 'z_length' (a name that violates the Java
coding conventions, which call for camel case and no underscores in
non-constant variable names) from the array 'length' attribute, it cannot be
used as an array index for the same array.  Arrays in Java do not change size,
and the maximum index of an array is one less than its length.  Trying to
reference array element 'zLength' (to correct your name) uses an index that is
out of bounds.
Fifth, if you want to add to an array, you need to create a longer array and
copy the 'zLength' elements of the old array into the first 'zLength' elements
of the new array.  Make sure the new array is long enough to handle all the
new elements you want to add (maximum index "length minus one").
For a self-growing array-like structure use a 'java.util.List' instead of an
array.  The 'java.util.ArrayList' is closest to a regular array and simplest
of the 'List' implementations.
Have you read the Java tutorials on java.sun.com?  If not, you must.  They
contain answers to some of the questions you asked.
--
Lew
Sorry, I just copied the code from my IDE and didn't think to replace
the tabs. The code that I pasted is the exact code I have compiled. I
apologize for using unclear terms such as "something like". I also
wasn't aware of the camel case convention. Here is a cleaner version
of the code:

import java.io.*;
import java.util.zip.*;
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.*;

public class ZIPImpl
{
public static void zipBlob(oracle.sql.BLOB srcBlob,
oracle.sql.BLOB dstBlob[],java.lang.String name)
{
try
{
int zLngth = dstBlob.length;

OutputStream outBuffer =
dstBlob[0].setBinaryStream(0);

InputStream inBuffer = srcBlob.getBinaryStream();
ZipOutputStream zip = new ZipOutputStream(outBuffer);
zip.setMethod(ZipOutputStream.DEFLATED);
byte[] tmpBuffer = new byte[1024];
ZipEntry entry = new ZipEntry(name);
zip.putNextEntry(entry);
int n;

while ((n = inBuffer.read(tmpBuffer)) >= 0)
{
zip.write(tmpBuffer, 0, n);
}

zip.close();

}
catch (SQLException e)
{
System.err.println(e);
}
catch (IOException e)
{
System.err.println(e);
}
}
}


For the oracle.sql.BLOB type, which alternate type would you
recommend? I realize that a BLOB is just a simple byte array. Would it
be better to go with java.sql.blob or would an ArrayList work? I just
went with the oracle version because I figured it would play nicer
with the database. Another issue I have run into is that zLngth is
null even when I am passing in the very same BLOB that the Java
procedure returned on the first iteration. I have read through every
single Java tutorial regarding BLOBs, zipping files, and Oracle. I
can't believe I forgot that arrays cannot be extended in Java. I will
try building a new ArrayList and copying over the old zipped BLOB
contents to it plus the new contents.

Thanks for your help.
cdef
2010-02-23 15:46:27 UTC
Permalink
After doing some tweaking and a lot of face-palming, I have reworked
my EXACT code and ended up with EXACTLY this:

CREATE OR REPLACE TYPE res_blob_zip AS TABLE OF BLOB
/

CREATE OR REPLACE TYPE RES_FILE_NAME_NT AS TABLE OF VARCHAR2(2000)
/


CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "ZIPImpl" AS
import java.io.*;
import java.util.zip.*;
import java.sql.Blob;
import oracle.sql.ARRAY;

public class ZIPImpl
{
public static void zipBlob(oracle.sql.ARRAY blobList,
oracle.sql.ARRAY nameList, java.sql.Blob[] outBlob) throws Exception
{
Blob[] blobs = (Blob[]) blobList.getArray();
String[] names = (String[]) nameList.getArray();

int blobCount = blobs.length;
int nameCount = names.length;

Blob zipLob = outBlob[0];

OutputStream os = zipLob.setBinaryStream(0);
zipLob = null;
ZipOutputStream zos = new ZipOutputStream(os);
int chunkSize = 32768;

//Now from this source Blob file, we need to get a stream and
then write that stream into Zipped Output
for (int i = 0; i<= (blobCount - 1); i++)
{
Blob src = blobs[i];

//Create a zip entry for the filename
ZipEntry entry = new ZipEntry(names[i]);
zos.putNextEntry(entry);

long len = src.length();
long offset = 1;
byte[] buffer;

while (offset < len)
{
buffer = src.getBytes(offset, chunkSize);

if (buffer == null)
break;

zos.write(buffer,0,buffer.length);
offset += buffer.length;
}

zos.closeEntry();
}

zos.close();
outBlob[0] = zipLob;
}
}
/


ALTER JAVA CLASS "ZIPImpl" RESOLVE
/


CREATE OR REPLACE PACKAGE res_zip
IS
PROCEDURE zipBlob(blob_list IN res_blob_zip,
name_list IN res_file_name_nt,
blob_zip OUT BLOB);

END res_zip;
/
CREATE OR REPLACE PACKAGE BODY res_zip
IS
PROCEDURE zipBlob(blob_list IN res_blob_zip,
name_list IN res_file_name_nt,
blob_zip OUT BLOB)
AS LANGUAGE JAVA
NAME
'ZIPImpl.zipBlob(oracle.sql.ARRAY,oracle.sql.ARRAY,java.sql.Blob[])';
END res_zip;
/


I have reworked my PL/SQL code to call the procedure zipBlob exactly
ONE time after filling the blob and filename tables to pass in as
arrays
res_zip.zipBlob(blob_list,name_list,blob_zip);


My issue now is that I am receiving the following error caused by the
declaration of "OutputStream os = zipLob.setBinaryStream(0);" in the
Java code:
Java call terminated by uncaught Java exception:
java.lang.NullPointerException

I have tried "OutputStream os = zipLob.setBinaryStream(1);" as well as
declaring zipBlob as "Blob zipLob = blobs[0];", and "Blob zipLob =
null;" but I still receive the error.

Any suggestions?
Lew
2010-02-23 16:08:40 UTC
Permalink
Post by cdef
After doing some tweaking and a lot of face-palming, I have reworked
CREATE OR REPLACE TYPE res_blob_zip AS TABLE OF BLOB
/
CREATE OR REPLACE TYPE RES_FILE_NAME_NT AS TABLE OF VARCHAR2(2000)
/
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "ZIPImpl" AS
import java.io.*;
import java.util.zip.*;
import java.sql.Blob;
import oracle.sql.ARRAY;
public class ZIPImpl
{
public static void zipBlob(oracle.sql.ARRAY blobList,
oracle.sql.ARRAY nameList, java.sql.Blob[] outBlob) throws Exception
{
Blob[] blobs = (Blob[]) blobList.getArray();
String[] names = (String[]) nameList.getArray();
int blobCount = blobs.length;
int nameCount = names.length;
Blob zipLob = outBlob[0];
Apparently 'outBlob[0]' is 'null'.

When you create a reference (non-primitive) array of a certain length, say
'n', all n entries are 'null' unless set to a different value explicitly.
Post by cdef
OutputStream os = zipLob.setBinaryStream(0);
zipLob = null;
ZipOutputStream zos = new ZipOutputStream(os);
int chunkSize = 32768;
//Now from this source Blob file, we need to get a stream and
then write that stream into Zipped Output
for (int i = 0; i<= (blobCount - 1); i++)
{
Blob src = blobs[i];
//Create a zip entry for the filename
ZipEntry entry = new ZipEntry(names[i]);
zos.putNextEntry(entry);
long len = src.length();
long offset = 1;
byte[] buffer;
while (offset < len)
{
buffer = src.getBytes(offset, chunkSize);
if (buffer == null)
break;
zos.write(buffer,0,buffer.length);
offset += buffer.length;
}
zos.closeEntry();
}
zos.close();
outBlob[0] = zipLob;
}
}
/
ALTER JAVA CLASS "ZIPImpl" RESOLVE
/
CREATE OR REPLACE PACKAGE res_zip
IS
PROCEDURE zipBlob(blob_list IN res_blob_zip,
name_list IN res_file_name_nt,
blob_zip OUT BLOB);
END res_zip;
/
CREATE OR REPLACE PACKAGE BODY res_zip
IS
PROCEDURE zipBlob(blob_list IN res_blob_zip,
name_list IN res_file_name_nt,
blob_zip OUT BLOB)
AS LANGUAGE JAVA
NAME
'ZIPImpl.zipBlob(oracle.sql.ARRAY,oracle.sql.ARRAY,java.sql.Blob[])';
END res_zip;
/
I have reworked my PL/SQL code to call the procedure zipBlob exactly
ONE time after filling the blob and filename tables to pass in as
arrays
res_zip.zipBlob(blob_list,name_list,blob_zip);
My issue now is that I am receiving the following error caused by the
declaration of "OutputStream os = zipLob.setBinaryStream(0);" in the
java.lang.NullPointerException
From the error message one can see that 'zipLob' is 'null'. If you
dereference a 'null' pointer (a.k.a. reference) you get that exception.
Post by cdef
I have tried "OutputStream os = zipLob.setBinaryStream(1);" as well as
You still have to set 'zipLob' to a non-'null' value first.
Post by cdef
declaring zipBlob [sic] as "Blob zipLob = blobs[0];", and "Blob zipLob =
null;" but I still receive the error.
Sure, because both those assignments must be (and the second one explicitly
is) assigning 'null' to 'zipLob'. In order to dereference a pointer
successfully it must be non-'null'.
--
Lew
cdef
2010-02-23 18:54:18 UTC
Permalink
Post by Lew
Post by cdef
After doing some tweaking and a lot of face-palming, I have reworked
CREATE OR REPLACE TYPE res_blob_zip AS TABLE OF BLOB
/
CREATE OR REPLACE TYPE RES_FILE_NAME_NT AS TABLE OF VARCHAR2(2000)
/
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "ZIPImpl" AS
import java.io.*;
import java.util.zip.*;
import java.sql.Blob;
import oracle.sql.ARRAY;
public class ZIPImpl
{
    public static void zipBlob(oracle.sql.ARRAY blobList,
oracle.sql.ARRAY nameList, java.sql.Blob[] outBlob) throws Exception
    {
        Blob[] blobs = (Blob[]) blobList.getArray();
        String[] names = (String[]) nameList.getArray();
        int blobCount = blobs.length;
        int nameCount = names.length;
        Blob zipLob = outBlob[0];
Apparently 'outBlob[0]' is 'null'.
When you create a reference (non-primitive) array of a certain length, say
'n', all n entries are 'null' unless set to a different value explicitly.
Post by cdef
        OutputStream os = zipLob.setBinaryStream(0);
        zipLob = null;
        ZipOutputStream zos = new ZipOutputStream(os);
        int chunkSize = 32768;
        //Now from this source Blob file, we need to get a stream and
then write that stream into Zipped Output
        for (int i = 0; i<= (blobCount - 1); i++)
        {
            Blob src = blobs[i];
            //Create a zip entry for the filename
            ZipEntry entry = new ZipEntry(names[i]);
            zos.putNextEntry(entry);
            long len = src.length();
            long offset = 1;
            byte[] buffer;
            while (offset < len)
            {
                buffer = src.getBytes(offset, chunkSize);
                if (buffer == null)
                    break;
                zos.write(buffer,0,buffer.length);
                offset += buffer.length;
            }
            zos.closeEntry();
        }
        zos.close();
        outBlob[0] = zipLob;
    }
}
/
ALTER JAVA CLASS "ZIPImpl" RESOLVE
/
CREATE OR REPLACE PACKAGE res_zip
IS
    PROCEDURE zipBlob(blob_list IN res_blob_zip,
                      name_list IN res_file_name_nt,
                      blob_zip OUT BLOB);
END res_zip;
/
CREATE OR REPLACE PACKAGE BODY res_zip
IS
    PROCEDURE zipBlob(blob_list IN res_blob_zip,
                      name_list IN res_file_name_nt,
                      blob_zip OUT BLOB)
                      AS LANGUAGE JAVA
                      NAME
'ZIPImpl.zipBlob(oracle.sql.ARRAY,oracle.sql.ARRAY,java.sql.Blob[])';
END res_zip;
/
I have reworked my PL/SQL code to call the procedure zipBlob exactly
ONE time after filling the blob and filename tables to pass in as
arrays
res_zip.zipBlob(blob_list,name_list,blob_zip);
My issue now is that I am receiving the following error caused by the
declaration of "OutputStream os = zipLob.setBinaryStream(0);" in the
java.lang.NullPointerException
 From the error message one can see that 'zipLob' is 'null'.  If you
dereference a 'null' pointer (a.k.a. reference) you get that exception.
Post by cdef
I have tried "OutputStream os = zipLob.setBinaryStream(1);" as well as
You still have to set 'zipLob' to a non-'null' value first.
Post by cdef
declaring zipBlob [sic] as "Blob zipLob = blobs[0];", and "Blob zipLob =
null;" but I still receive the error.
Sure, because both those assignments must be (and the second one explicitly
is) assigning 'null' to 'zipLob'.  In order to dereference a pointer
successfully it must be non-'null'.
--
Lew
Thanks, that was indeed the issue. The solution that worked for me was
to create a temporary blob. This also addressed another issue with
Java/Oracle attempting to overwrite the BLOB in the table with the new
zip BLOB.

In case anyone else runs into this in the future, here is my working,
somewhat finalized code (still could use a little cleanup):

CREATE OR REPLACE JAVA SOURCE NAMED "ZIPImpl" AS
import java.io.*;
import java.util.zip.*;
import java.sql.Blob;
import oracle.sql.ARRAY;
import oracle.sql.*;
import java.sql.*;
import oracle.jdbc.*;

public class ZIPImpl {
public static void zipBlob(oracle.sql.ARRAY
blobList,oracle.sql.ARRAY nameList,java.sql.Blob[] outBlob) throws
Exception {
Connection conn =
DriverManager.getConnection("jdbc:default:connection:");
Blob[] blobs = (Blob[]) blobList.getArray();
String[] names = (String[]) nameList.getArray();
int blobCount = blobs.length;
int nameCount = names.length;
Blob zipLob = BLOB.createTemporary(conn, false,
BLOB.DURATION_SESSION);
OutputStream os = zipLob.setBinaryStream(1);
ZipOutputStream zos = new ZipOutputStream(os);
int chunkSize = 32768;
//Now from this source Blob file, we need to get a stream and
then write that stream into Zipped Output
for (int i = 0; i<= (blobCount - 1); i++) {
Blob src = blobs[i];
//Create a zip entry for the filename
ZipEntry entry = new ZipEntry(names[i]);
zos.putNextEntry(entry);

long len = src.length();
long offset = 1;
byte[] buffer;

while (offset < len) {
buffer = src.getBytes(offset, chunkSize);
if (buffer == null)
break;
zos.write(buffer,0,buffer.length);
offset += buffer.length;
}
zos.closeEntry();
}
zos.close();
outBlob[0] = zipLob;
}
}
/

Thanks to all who had the patience to help me with this. I really do
appreciate it.
John B. Matthews
2010-02-23 19:15:17 UTC
Permalink
In article
Post by cdef
Thanks to all who had the patience to help me with this. I really do
appreciate it.
Thank you for taking time to follow up with your results.
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
Continue reading on narkive:
Loading...