From 5136bbc8d33fab04e782e915bb6669599870f099 Mon Sep 17 00:00:00 2001 From: Michael Dick Date: Wed, 22 Jul 2009 23:09:02 +0000 Subject: [PATCH] OPENJPA-922: Allow DB2 to use setByteArrayInputStream instead of setBytes when needed. Submitted by : B. J. Reed git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@796907 13f79535-47bb-0310-9956-ffa450edef68 --- .../openjpa/jdbc/sql/DB2Dictionary.java | 59 +++++++++++++ .../persistence/fields/ByteArrayHolder.java | 61 +++++++++++++ .../persistence/fields/TestByteArray.java | 88 +++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fields/ByteArrayHolder.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fields/TestByteArray.java diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java index e82a5a69b..2956dc063 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java @@ -18,10 +18,13 @@ */ package org.apache.openjpa.jdbc.sql; +import java.io.ByteArrayInputStream; import java.lang.reflect.Method; +import java.sql.Blob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.Arrays; @@ -913,4 +916,60 @@ public class DB2Dictionary super.setQueryTimeout(stmnt, timeout); } } + + /** + * Set the given value as a parameter to the statement. + */ + public void setBytes(PreparedStatement stmnt, int idx, byte[] val, + Column col) + throws SQLException { + // for DB2, if the column was defined as CHAR for BIT DATA, then + // we want to use the setBytes in stead of the setBinaryStream + if (useSetBytesForBlobs + || (col.getTypeName() != null && col.getTypeName().contains("BIT DATA"))) { + stmnt.setBytes(idx, val); + } else { + setBinaryStream(stmnt, idx, new ByteArrayInputStream(val), val.length, col); + } + } + + /** + * Convert the specified column of the SQL ResultSet to the proper + * java type. + */ + public byte[] getBytes(ResultSet rs, int column) + throws SQLException { + if (useGetBytesForBlobs) { + return rs.getBytes(column); + } + if (useGetObjectForBlobs) { + return (byte[]) rs.getObject(column); + } + + // At this point we don't have any idea if the DB2 column was defined as + // a blob or if it was defined as CHAR for BIT DATA. + // First try as a blob, if that doesn't work, then try as CHAR for BIT DATA + // If that doesn't work, then go ahead and throw the first exception + try { + Blob blob = getBlob(rs, column); + if (blob == null) { + return null; + } + + int length = (int) blob.length(); + if (length == 0) { + return null; + } + + return blob.getBytes(1, length); + } + catch (SQLException e) { + try { + return rs.getBytes(column); + } + catch (SQLException e2) { + throw e; + } + } + } } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fields/ByteArrayHolder.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fields/ByteArrayHolder.java new file mode 100644 index 000000000..070df428c --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fields/ByteArrayHolder.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.fields; + +import java.io.Serializable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.GeneratedValue; + +import static javax.persistence.GenerationType.IDENTITY; + +@Entity +public class ByteArrayHolder implements Serializable { + @Id + @Column(name="TASK_ID") + @GeneratedValue(strategy=IDENTITY) + private int taskId; + + @Column(columnDefinition="CHAR(16) FOR BIT DATA NOT NULL") // type 1004 size -1 should be size 0 + //@Lob //type 1004 size -1 should be 1003 + private byte[] tkiid; + + private static final long serialVersionUID = 1L; + + public ByteArrayHolder() { + super(); + } + + public int getTaskId() { + return this.taskId; + } + + public void setTaskId(int taskId) { + this.taskId = taskId; + } + + public byte[] getTkiid() { + return this.tkiid; + } + + public void setTkiid(byte[] tkiid) { + this.tkiid = tkiid; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fields/TestByteArray.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fields/TestByteArray.java new file mode 100644 index 000000000..7bda2ca78 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/fields/TestByteArray.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.fields; + +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; +import org.apache.openjpa.jdbc.sql.DB2Dictionary; +import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; +import org.apache.openjpa.persistence.test.SingleEMTestCase; + +/* + * This tests a particular kind of byte [] that is not a BLOB for DB2. Don't need to + * do anything except return if we are using a different DB. + */ +public class TestByteArray extends SingleEMTestCase { + boolean runTest=false; + + public void setUp() { + super.setUp(); + OpenJPAEntityManagerFactorySPI ojpaEmf = (OpenJPAEntityManagerFactorySPI) emf; + JDBCConfiguration conf = (JDBCConfiguration) ojpaEmf.getConfiguration(); + if (conf.getDBDictionaryInstance() instanceof DB2Dictionary) { + runTest = true; + super.setUp(ByteArrayHolder.class, CLEAR_TABLES); + } + } + + @SuppressWarnings("unchecked") + public void testByteArray() { + if (! runTest) { + // skip if not DB2 (from setup) + System.out.println("MDD skipping"); + return; + } + + EntityManager em = emf.createEntityManager(); + EntityManager em2 = emf.createEntityManager(); + + byte[] ba = + new byte[] { (byte) 0xa0, (byte) 0x1b, (byte) 0x01, (byte) 0x1f, + (byte) 0x38, (byte) 0xcf, (byte) 0x67, (byte) 0x35, + (byte) 0x55, (byte) 0x43, (byte) 0xd9, (byte) 0xf6, + (byte) 0x71, (byte) 0x5e, (byte) 0x00, (byte) 0x00 }; + ByteArrayHolder holder = new ByteArrayHolder(); + holder.setTkiid(ba); + try { + em.getTransaction().begin(); + em.persist(holder); + em.getTransaction().commit(); + } catch(Throwable t) { + t.printStackTrace(); + fail("Error: Task insert failed"); + } + + // verify that the get works + Query q = em2.createQuery("select e from ByteArrayHolder e"); + List elist = q.getResultList(); + for (ByteArrayHolder e : elist) { + String baFromH = new String(e.getTkiid()); + assertEquals(new String (ba), baFromH); + } + + // verify that it's still in the original EntityManager + holder = em.find(ByteArrayHolder.class, holder.getTaskId()); + String baFromH = new String(holder.getTkiid()); + assertEquals(new String (ba), baFromH); + } +}