View Javadoc
1   package org.dbunit.ext.postgresql;
2   
3   import org.dbunit.dataset.datatype.BytesDataType;
4   import org.dbunit.dataset.datatype.TypeCastException;
5   import org.postgresql.PGConnection;
6   import org.postgresql.largeobject.LargeObject;
7   import org.postgresql.largeobject.LargeObjectManager;
8   import org.slf4j.Logger;
9   import org.slf4j.LoggerFactory;
10  
11  import java.io.ByteArrayInputStream;
12  import java.sql.*;
13  
14  public class PostgreSQLOidDataType
15          extends BytesDataType {
16  
17      /**
18       * Logger for this class
19       */
20      private static final Logger logger = LoggerFactory.getLogger(PostgreSQLOidDataType.class);
21  
22      public PostgreSQLOidDataType() {
23          super("OID", Types.BIGINT);
24      }
25  
26      @Override
27      public Object getSqlValue(final int column, final ResultSet resultSet)
28              throws SQLException,
29              TypeCastException
30      {
31          logger.debug("getSqlValue(column={}, resultSet={}) - start", column, resultSet);
32  
33          Statement statement = resultSet.getStatement();
34          Connection connection = statement.getConnection();
35          boolean autoCommit = connection.getAutoCommit();
36          // kinda ugly
37          connection.setAutoCommit(false);
38  
39          try {
40              PGConnection pgConnection = connection.unwrap(PGConnection.class);
41              LargeObjectManager lobj = pgConnection.getLargeObjectAPI();
42  
43              long oid = resultSet.getLong(column);
44              if (oid == 0) {
45                  logger.debug("'oid' is zero, the data is NULL.");
46                  return null;
47              }
48              LargeObject obj = lobj.open(oid, LargeObjectManager.READ);
49              // If lobj.open() throws an exception, it means something wrong with the OID / table.
50              // So to be accurate, we don't catch this exception but let it propagate.
51              // Swallowing the exception silently indeed hides the problem, which is the wrong behavior
52  //            try {
53  //                obj = lobj.open(oid, LargeObjectManager.READ);
54  //            } catch (SQLException ex) {
55  //                logger.error("Failed to open oid {} for Large Object reading.", oid);
56  //                logger.error("Exception: {}", ex.getMessage());
57  //                logger.error("Returning null instead of bailing out");
58  //                return null;
59  //            }
60  
61              // Read the data
62              byte buf[] = new byte[obj.size()];
63              obj.read(buf, 0, obj.size());
64              // Close the object
65              obj.close();
66  
67              return buf;
68          } finally {
69              connection.setAutoCommit(autoCommit);
70          }
71      }
72  
73      @Override
74      public void setSqlValue(final Object value, final int column, final PreparedStatement statement)
75              throws SQLException, TypeCastException
76      {
77          logger.debug("setSqlValue(value={}, column={}, statement={}) - start",
78              value, column, statement);
79  
80          Connection connection = statement.getConnection();
81          boolean autoCommit = connection.getAutoCommit();
82          // kinda ugly
83          connection.setAutoCommit(false);
84  
85          try {
86              // Get the Large Object Manager to perform operations with
87              LargeObjectManager lobj = (connection.unwrap(PGConnection.class)).getLargeObjectAPI();
88  
89              // Create a new large object
90              long oid = lobj.createLO(LargeObjectManager.READ | LargeObjectManager.WRITE);
91  
92              // Open the large object for writing
93              LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);
94  
95              // Now open the file
96              ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) super.typeCast(value));
97  
98              // Copy the data from the file to the large object
99              byte buf[] = new byte[2048];
100             int s = 0;
101             while ((s = bis.read(buf, 0, 2048)) > 0) {
102                 obj.write(buf, 0, s);
103             }
104 
105             // Close the large object
106             obj.close();
107 
108             statement.setLong(column, oid);
109         } finally {
110             connection.setAutoCommit(autoCommit);
111         }
112     }
113 }