简体   繁体   中英

Comparing a byte value with a bytea column in postgresql

I am using PostgreSQL as my database and java servlet to communicate with PostgreSQL. My application requires that I fetch data from database for a matching input file. All the files are stored in the database in a bytea column. This is my code:

String checkdb="select * from key where certificate = '"+c+"';";
Statement stcheck=conn.createStatement(
    ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet newrs=stcheck.executeQuery(checkdb);
newrs.last();
int rowcount=newrs.getRow();
if(rowcount!=0)
throw new ArithmeticException();

where certificate is the name of the column containing the bytea data and c (uploaded) is a certificate in byte[] form. So here I am checking if the uploaded certificate is already present in the database. If it is present then I am throwing an exception.

But the problem is uploading the same certificate multiple times is not throwing an exception is working as if the two certificates are different.

Am I comparing the byte values correctly. What should I do to correct this?
EDIT
I tried setting the certificate column as the primary key. But still the certificate gets inserted into the database. How could this happen? The internal comparison also fails for some reason.
EDIT
I tried retrieving a ile and converted it to string :

InputStream input13 = retrs.getBinaryStream("certificate");
       ByteArrayOutputStream output13 = new ByteArrayOutputStream();
         byte buf[]=new byte[1024];
            int len;
    IOUtils.copy(input13, output13);
    input13.close();
    byte[] retvalue=output13.toByteArray();
    String s1=new String(retvalue);

String s2=new String(c);
System.out.println("in--------------"+s2);


System.out.println("out----------------"+s1);


retrs is the result set containing the just stored certificate. c is the input certificate in byte[]. The out put that I get is:

19:05:43,156 INFO  [STDOUT] in-------------------BEGIN CERTIFICATE-----
MIICIjCCAYsCAQMwDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCYXMxCzAJBgNV
BAgMAmFzMQswCQYDVQQHDAJhczELMAkGA1UECgwCYXMxCzAJBgNVBAsMAmFzMQsw
CQYDVQQDDAJjYTERMA8GCSqGSIb3DQEJARYCYXMwHhcNMTIwNDEwMDY0ODQ3WhcN
MTMwNDEwMDY0ODQ3WjBSMQswCQYDVQQGEwJhczELMAkGA1UECBMCYXMxCzAJBgNV
BAcTAmFzMQswCQYDVQQKEwJhczELMAkGA1UECxMCYXMxDzANBgNVBAMTBmNsaWVu
dDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsfJq9TVgTLqz84nuWpDm+dvI
do2HIWoHkmEPNowK4xn1+qWUPCy30aASWI92YMtE6njtQGyZBYij0iTAxldDktqd
bMdpKAONDlSv71rn+fZPuyenbBFYZexybNVsRMFzTD/F/hiPPXT7E1j9CrgIMxVz
ScZeNATh/dPLwuNQ0dsCAwEAATANBgkqhkiG9w0BAQUFAAOBgQDDUyeIWlKaMMkM
8VRGuDJyKFC8miQfmul6zE4+6RTswHKjcUoje2vhTQgV+GBfqx8ai+ziujx8CeyR
eJWcb1G8gg+LMUNDcTOlXTeBG9L2c/gMOEu7BEjtpojSYmFyEvJEQ5Yep44HKZZb
FSPFVNxGiXBhNxtKQdAu6/smQ/eBNg==
-----END CERTIFICATE-----
19:05:43,156 INFO  [STDOUT] out----------------[B@17f8b39


Is my way of retrieving wrong. Because [B@17f8b39 looks like a memory location or something like that.
Answer
As said by @jarnbjo One thing has to be kept in mind. When ever you use byte array in postgressql whether for retieving or inserting do it only using the setBytes() .Else only the memory location(hash code in java) of the byte[] gets inserted.

Use a PreparedStatement:

PreparedStatement pstat = conn.prepareStatement(
      "select * from key where certificate = ?");
pstat.setBytes(1, c);
ResultSet newrs = pstat.executeQuery();

You should of course do the same when inserting the data as well.

Clearly you are not doing the comparison correctly based on the results you are seeing. You need to do some debugging to figure out where things are going wrong. I'd suggest a simple test along the following lines:

  • start with a clean database
  • obtain a certificate from the client
  • insert it into the database
  • read it back out again immediately (it should be the only one)- compare the data you inserted with the data you read back. They should be the same. If they are not the same, figure out why
  • Once that works, extend the test case to run a query like the one in your question. If that returns zero records, figure out why.

In terms of figuring out why there are differences, you may find it helpful to start wth a simple test case where you insert a simple byte array - such as one consisting of a single byte.

I would recommend you generate file's checksum and store in db, and check the file content based on the checksum instead of the file's bytes

table key{
    id int,
    certificate blob,
    checksum varchar(32)
}

And use the following method to generate checksum of byte[] buffer

public String getCheckSum(byte[] buffer) {
    StringBuilder builder = new StringBuilder();
    try {
        MessageDigest complete;
        complete = MessageDigest.getInstance("MD5");
        byte[] rawCheckSum = complete.digest(buffer);
        for(byte b: rawCheckSum) {
            builder.append(Integer.toString( ( b & 0xff ) + 0x100, 16).substring( 1 ));
        }
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
    return builder.toString();
}

Finally,

String checkdb="select * from key where checksum = '" + getCheckSum(c) + "';";

Edit:

When insert bytes into db, you should use:

String query = "INSERT INTO key (certificate) VALUES (?)";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setBytes(1, c);

Instead of

String query = "INSERT INTO key (certificate) VALUES ('" + c + "')";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.execute();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM