some code cleanup. removed unnecessary semikolons, unused vars, etc.
[mir.git] / source / mir / storage / Database.java
index 9876791..0f886db 100755 (executable)
  */
 package mir.storage;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
 import mir.config.MirPropertiesConfiguration;
+import mir.entity.AbstractEntity;
 import mir.entity.Entity;
 import mir.entity.EntityList;
 import mir.entity.StorableObjectEntity;
 import mir.log.LoggerWrapper;
 import mir.misc.StringUtil;
-import mir.storage.store.*;
+import mir.storage.store.ObjectStore;
+import mir.storage.store.StorableObject;
+import mir.storage.store.StoreContainerType;
+import mir.storage.store.StoreIdentifier;
+import mir.storage.store.StoreUtil;
 import mir.util.JDBCStringRoutines;
 import mircoders.global.MirGlobal;
 
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.sql.*;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.*;
+import org.apache.commons.dbcp.DelegatingConnection;
+import org.postgresql.PGConnection;
+import org.postgresql.largeobject.LargeObject;
+import org.postgresql.largeobject.LargeObjectManager;
 
 /**
  * Implements database access.
  *
- * @version $Id: Database.java,v 1.44.2.23 2004/11/21 22:07:13 zapata Exp $
+ * @version $Id: Database.java,v 1.44.2.27 2005/02/10 16:22:33 rhindes Exp $
  * @author rk
  *
  */
-public class Database implements StorageObject {
+public class Database {
   private static Class GENERIC_ENTITY_CLASS = mir.entity.StorableObjectEntity.class;
   protected static final ObjectStore o_store = ObjectStore.getInstance();
   private static final int _millisPerHour = 60 * 60 * 1000;
@@ -69,9 +92,9 @@ public class Database implements StorageObject {
 
   protected List fieldNames;
   protected int[] fieldTypes;
+  protected Map fieldNameToType;
 
-  protected Class theEntityClass;
-  protected boolean hasTimestamp = true;
+  protected Class entityClass;
   private int defaultLimit;
 
   TimeZone timezone;
@@ -100,7 +123,7 @@ public class Database implements StorageObject {
     defaultLimit = Integer.parseInt(configuration.getString("Database.Limit"));
 
     try {
-      theEntityClass = GENERIC_ENTITY_CLASS;
+      entityClass = GENERIC_ENTITY_CLASS;
     }
     catch (Throwable e) {
       logger.error("Error in Database() constructor with " + theAdaptorName + " -- " + e.getMessage());
@@ -108,15 +131,20 @@ public class Database implements StorageObject {
     }
   }
 
-  /**
-   * Liefert die Entity-Klasse zur?ck, in der eine Datenbankzeile gewrappt
-   * wird. Wird die Entity-Klasse durch die erbende Klasse nicht ?berschrieben,
-   * wird eine mir.entity.GenericEntity erzeugt.
-   *
-   * @return Class-Objekt der Entity
-   */
   public java.lang.Class getEntityClass() {
-    return theEntityClass;
+    return entityClass;
+  }
+
+  public Entity createNewEntity() throws StorageObjectFailure {
+    try {
+      AbstractEntity result = (AbstractEntity) entityClass.newInstance();
+      result.setStorage(this);
+
+      return result;
+    }
+    catch (Throwable t) {
+      throw new StorageObjectFailure(t);
+    }
   }
 
   /**
@@ -129,12 +157,7 @@ public class Database implements StorageObject {
     return defaultLimit;
   }
 
-  /**
-   * Liefert den Namen des Primary-Keys zur?ck. Wird die Variable nicht von
-   * der erbenden Klasse ?berschrieben, so ist der Wert <code>PKEY</code>
-   * @return Name des Primary-Keys
-   */
-  public String getIdName() {
+  public String getIdFieldName() {
     return primaryKeyField;
   }
 
@@ -162,11 +185,11 @@ public class Database implements StorageObject {
   }
 
   /**
-   * {@inheritDoc}
+   * Returns a list of field names for this <code>Database</code>
    */
   public List getFieldNames() throws StorageObjectFailure {
     if (fieldNames == null) {
-      retrieveMetaData();
+      acquireMetaData();
     }
 
     return fieldNames;
@@ -315,14 +338,14 @@ public class Database implements StorageObject {
     }
 
     // ask object store for object
-    if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+    if (StoreUtil.extendsStorableEntity(entityClass)) {
       String uniqueId = id;
 
-      if (theEntityClass.equals(StorableObjectEntity.class)) {
+      if (entityClass.equals(StorableObjectEntity.class)) {
         uniqueId += ("@" + mainTable);
       }
 
-      StoreIdentifier search_sid = new StoreIdentifier(theEntityClass, uniqueId);
+      StoreIdentifier search_sid = new StoreIdentifier(entityClass, uniqueId);
       logger.debug("CACHE: (dbg) looking for sid " + search_sid.toString());
 
       Entity hit = (Entity) o_store.use(search_sid);
@@ -488,7 +511,6 @@ public class Database implements StorageObject {
     // cause StringUtil.splitString puts in emptyString
 
     if (anExtraTables!=null && ((String) anExtraTables.get(0)).trim().equals("")){
-      logger.debug("+++ made anExtraTables to null!");
       anExtraTables=null;
     }
 
@@ -503,8 +525,8 @@ public class Database implements StorageObject {
     // check o_store for entitylist
     // only if no relational select
     if (anExtraTables==null) {
-      if (StoreUtil.extendsStorableEntity(theEntityClass)) {
-         StoreIdentifier searchSid = new StoreIdentifier(theEntityClass,
+      if (StoreUtil.extendsStorableEntity(entityClass)) {
+         StoreIdentifier searchSid = new StoreIdentifier(entityClass,
                StoreContainerType.STOC_TYPE_ENTITYLIST,
                StoreUtil.getEntityListUniqueIdentifierFor(mainTable,
                 aWhereClause, anOrderByClause, anOffset, aLimit));
@@ -522,17 +544,12 @@ public class Database implements StorageObject {
     Statement statement = null;
     ResultSet resultSet;
 
-    int offsetCount = 0;
-    int count = 0;
-
     // build sql-statement
 
     if ((aWhereClause != null) && (aWhereClause.trim().length() == 0)) {
       aWhereClause = null;
     }
 
-    StringBuffer countSql =
-      new StringBuffer("select count(*) from ").append(useTable);
     StringBuffer selectSql =
       new StringBuffer("select "+selection+" from ").append(useTable);
 
@@ -540,7 +557,6 @@ public class Database implements StorageObject {
     if (anExtraTables!=null) {
       for (int i=0;i < anExtraTables.size();i++) {
         if (!anExtraTables.get(i).equals("")) {
-          countSql.append( ", " + anExtraTables.get(i));
           selectSql.append( ", " + anExtraTables.get(i));
         }
       }
@@ -548,7 +564,6 @@ public class Database implements StorageObject {
 
     if (aWhereClause != null) {
       selectSql.append(" where ").append(aWhereClause);
-      countSql.append(" where ").append(aWhereClause);
     }
 
     if ((anOrderByClause != null) && !(anOrderByClause.trim().length() == 0)) {
@@ -556,13 +571,14 @@ public class Database implements StorageObject {
     }
 
     if ((aLimit > -1) && (anOffset > -1)) {
-      selectSql.append(" LIMIT ").append(aLimit).append(" OFFSET ").append(anOffset);
+      selectSql.append(" LIMIT ").append(aLimit+1).append(" OFFSET ").append(anOffset);
     }
 
     // execute sql
     try {
       connection = obtainConnection();
       statement = connection.createStatement();
+      boolean hasMore = false;
 
       // selecting...
       resultSet = executeSql(statement, selectSql.toString());
@@ -570,54 +586,29 @@ public class Database implements StorageObject {
       if (resultSet != null) {
         theReturnList = new EntityList();
         Entity theResultEntity;
-        while (resultSet.next()) {
+        int position = 0;
+        while (((aLimit == -1) || (position<aLimit)) && resultSet.next()) {
           theResultEntity = makeEntityFromResultSet(resultSet);
           theReturnList.add(theResultEntity);
-          offsetCount++;
+          position++;
         }
+        hasMore = resultSet.next();
         resultSet.close();
       }
 
-      // making entitylist infos
-      count = offsetCount;
-
       if (theReturnList != null) {
         // now we decide if we have to know an overall count...
-        count = offsetCount;
-
-        if ((aLimit > -1) && (anOffset > -1)) {
-          if (offsetCount == aLimit) {
-            resultSet = executeSql(statement, countSql.toString());
-
-            if (resultSet != null) {
-              if (resultSet.next()) {
-                count = resultSet.getInt(1);
-              }
-
-              resultSet.close();
-            }
-            else {
-              logger.error("Could not count: " + countSql);
-            }
-          }
-        }
-
-        theReturnList.setCount(count);
         theReturnList.setOffset(anOffset);
         theReturnList.setWhere(aWhereClause);
         theReturnList.setOrder(anOrderByClause);
         theReturnList.setStorage(this);
         theReturnList.setLimit(aLimit);
 
-        if (anOffset >= aLimit) {
-          theReturnList.setPrevBatch(anOffset - aLimit);
-        }
-
-        if ((anOffset + offsetCount) < count) {
+        if (hasMore) {
           theReturnList.setNextBatch(anOffset + aLimit);
         }
 
-        if (anExtraTables==null && StoreUtil.extendsStorableEntity(theEntityClass)) {
+        if (anExtraTables==null && StoreUtil.extendsStorableEntity(entityClass)) {
           StoreIdentifier sid = theReturnList.getStoreIdentifier();
           logger.debug("CACHE (add): " + sid.toString());
           o_store.add(sid);
@@ -639,12 +630,6 @@ public class Database implements StorageObject {
     return theReturnList;
   }
 
-  /**
-   *  Bastelt aus einer Zeile der Datenbank ein EntityObjekt.
-   *
-   *  @param rs Das ResultSetObjekt.
-   *  @return Entity Die Entity.
-   */
   private Entity makeEntityFromResultSet(ResultSet rs)
     throws StorageObjectFailure {
     Map theResultHash = new HashMap();
@@ -653,9 +638,9 @@ public class Database implements StorageObject {
     Entity returnEntity = null;
 
     try {
-      if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+      if (StoreUtil.extendsStorableEntity(entityClass)) {
          StoreIdentifier searchSid = StorableObjectEntity.getStoreIdentifier(this,
-               theEntityClass, rs);
+               entityClass, rs);
          Entity hit = (Entity) o_store.use(searchSid);
          if (hit != null) return hit;
       }
@@ -693,9 +678,8 @@ public class Database implements StorageObject {
         }
       }
 
-      if (theEntityClass != null) {
-        returnEntity = (Entity) theEntityClass.newInstance();
-        returnEntity.setStorage(this);
+      if (entityClass != null) {
+        returnEntity = createNewEntity();
         returnEntity.setFieldValues(theResultHash);
 
         if (returnEntity instanceof StorableObject) {
@@ -703,18 +687,12 @@ public class Database implements StorageObject {
           o_store.add(((StorableObject) returnEntity).getStoreIdentifier());
         }
       } else {
-        throwStorageObjectException("Internal Error: theEntityClass not set!");
+        throwStorageObjectException("Internal Error: entityClass not set!");
       }
     }
-    catch (IllegalAccessException e) {
-      throwStorageObjectException("No access! -- " + e.getMessage());
-    }
     catch (IOException e) {
       throwStorageObjectException("IOException! -- " + e.getMessage());
     }
-    catch (InstantiationException e) {
-      throwStorageObjectException("No Instatiation! -- " + e.getMessage());
-    }
     catch (SQLException sqe) {
       throwSQLException(sqe, "makeEntityFromResultSet");
 
@@ -727,10 +705,10 @@ public class Database implements StorageObject {
   /**
    * Inserts an entity into the database.
    *
-   * @param theEntity
+   * @param anEntity
    * @return der Wert des Primary-keys der eingef?gten Entity
    */
-  public String insert(Entity theEntity) throws StorageObjectFailure {
+  public String insert(Entity anEntity) throws StorageObjectFailure {
     invalidateStore();
 
     String returnId = null;
@@ -752,16 +730,16 @@ public class Database implements StorageObject {
           aValue = null;
 
           // exceptions
-          if (!theEntity.hasFieldValue(aField) && (
+          if (!anEntity.hasFieldValue(aField) && (
               aField.equals("webdb_create") ||
               aField.equals("webdb_lastchange"))) {
             aValue = "NOW()";
           }
           else {
-              if (theEntity.hasFieldValue(aField)) {
+              if (anEntity.hasFieldValue(aField)) {
                 aValue =
                   "'" +
-                   JDBCStringRoutines.escapeStringLiteral(theEntity.getFieldValue(aField)) + "'";
+                   JDBCStringRoutines.escapeStringLiteral(anEntity.getFieldValue(aField)) + "'";
               }
           }
 
@@ -788,7 +766,7 @@ public class Database implements StorageObject {
                                         .append(") values (").append(v).append(")");
       String sql = sqlBuf.toString();
 
-      logger.info("INSERT: " + sql);
+      logQueryBefore(sql);
       con = obtainConnection();
       con.setAutoCommit(false);
       pstmt = con.prepareStatement(sql);
@@ -803,7 +781,7 @@ public class Database implements StorageObject {
 //      pstmt = con.prepareStatement("select currval('" +  + "_id_seq')");
 
       returnId = getLatestInsertedId(con);
-      theEntity.setId(returnId);
+      anEntity.setId(returnId);
     }
     catch (SQLException sqe) {
       throwSQLException(sqe, "insert");
@@ -907,7 +885,7 @@ public class Database implements StorageObject {
     }
 
     sql.append(" where id=").append(id);
-    logger.info("UPDATE: " + sql);
+    logQueryBefore(sql.toString());
 
     try {
       con = obtainConnection();
@@ -924,7 +902,8 @@ public class Database implements StorageObject {
         con.setAutoCommit(true);
       }
       catch (Exception e) {
-        ;
+        
+       
       }
 
       freeConnection(con, pstmt);
@@ -938,17 +917,17 @@ public class Database implements StorageObject {
    */
   public boolean delete(String id) throws StorageObjectFailure {
     // ostore send notification
-    if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+    if (StoreUtil.extendsStorableEntity(entityClass)) {
       String uniqueId = id;
 
-      if (theEntityClass.equals(StorableObjectEntity.class)) {
+      if (entityClass.equals(StorableObjectEntity.class)) {
         uniqueId += ("@" + mainTable);
       }
 
       logger.debug("CACHE: (del) " + id);
 
       StoreIdentifier search_sid =
-        new StoreIdentifier(theEntityClass,
+        new StoreIdentifier(entityClass,
           StoreContainerType.STOC_TYPE_ENTITY, uniqueId);
       o_store.invalidate(search_sid);
     }
@@ -960,7 +939,7 @@ public class Database implements StorageObject {
     String sql =
       "delete from " + mainTable + " where " + primaryKeyField + "='" + id + "'";
 
-    logger.debug("DELETE " + sql);
+    logQueryBefore(sql);
     try {
       con = obtainConnection();
       stmt = con.createStatement();
@@ -980,10 +959,6 @@ public class Database implements StorageObject {
 
   /**
    * Deletes entities based on a where clause
-   *
-   * @param aWhereClause
-   * @return
-   * @throws StorageObjectFailure
    */
   public int deleteByWhereClause(String aWhereClause) throws StorageObjectFailure {
     invalidateStore();
@@ -1025,15 +1000,15 @@ public class Database implements StorageObject {
   public ResultSet executeSql(Statement stmt, String sql)
                             throws StorageObjectFailure, SQLException {
     ResultSet rs;
+    logQueryBefore(sql);
     long startTime = System.currentTimeMillis();
-
     try {
       rs = stmt.executeQuery(sql);
 
-      logger.info((System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+      logQueryAfter(sql, (System.currentTimeMillis() - startTime));
     }
     catch (SQLException e) {
-      logger.error(e.getMessage() +"\n" + (System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+      logQueryError(sql, (System.currentTimeMillis() - startTime), e);
       throw e;
     }
 
@@ -1056,6 +1031,10 @@ public class Database implements StorageObject {
     }
   }
 
+  /**
+   * Executes 1 sql statement and returns the results as a <code>List</code> of
+   * <code>Map</code>s
+   */
   public List executeFreeSql(String sql, int aLimit) throws StorageObjectFailure, StorageObjectExc {
     Connection connection = null;
     Statement statement = null;
@@ -1083,16 +1062,19 @@ public class Database implements StorageObject {
         freeConnection(connection, statement);
       }
     }
-  };
+  }
 
+  /**
+   * Executes 1 sql statement and returns the first result row as a <code>Map</code>s
+   * (<code>null</code> if there wasn't any row)
+   */
   public Map executeFreeSingleRowSql(String anSqlStatement) throws StorageObjectFailure, StorageObjectExc {
     try {
       List resultList = executeFreeSql(anSqlStatement, 1);
       try {
         if (resultList.size()>0)
           return (Map) resultList.get(0);
-        else
-          return null;
+                               return null;
       }
       finally {
       }
@@ -1100,8 +1082,12 @@ public class Database implements StorageObject {
     catch (Throwable t) {
       throw new StorageObjectFailure(t);
     }
-  };
+  }
 
+  /**
+   * Executes 1 sql statement and returns the first column of the first result row as a <code>String</code>s
+   * (<code>null</code> if there wasn't any row)
+   */
   public String executeFreeSingleValueSql(String sql) throws StorageObjectFailure, StorageObjectExc {
     Map row = executeFreeSingleRowSql(sql);
 
@@ -1111,9 +1097,8 @@ public class Database implements StorageObject {
     Iterator i = row.values().iterator();
     if (i.hasNext())
       return (String) i.next();
-    else
-      return null;
-  };
+               return null;
+  }
 
   public int getSize(String where) throws SQLException, StorageObjectFailure {
     return getSize("", null, where);
@@ -1123,8 +1108,6 @@ public class Database implements StorageObject {
    */
   public int getSize(String mainTablePrefix, List extraTables, String where) throws SQLException, StorageObjectFailure {
 
-    long startTime = System.currentTimeMillis();
-
     String useTable = mainTable;
     if (mainTablePrefix!=null && mainTablePrefix.trim().length()>0) {
       useTable+=" "+mainTablePrefix;
@@ -1147,6 +1130,8 @@ public class Database implements StorageObject {
     Connection con = null;
     Statement stmt = null;
     int result = 0;
+    logQueryBefore(countSql.toString());
+    long startTime = System.currentTimeMillis();
 
     try {
       con = obtainConnection();
@@ -1164,7 +1149,7 @@ public class Database implements StorageObject {
     finally {
       freeConnection(con, stmt);
     }
-    logger.info((System.currentTimeMillis() - startTime) + "ms. for: " + countSql);
+    logQueryAfter(countSql.toString(), (System.currentTimeMillis() - startTime));
 
     return result;
   }
@@ -1172,15 +1157,17 @@ public class Database implements StorageObject {
   public int executeUpdate(Statement stmt, String sql)
     throws StorageObjectFailure, SQLException {
     int rs;
+
+    logQueryBefore(sql);
     long startTime = System.currentTimeMillis();
 
     try {
       rs = stmt.executeUpdate(sql);
 
-      logger.info((System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+      logQueryAfter(sql, (System.currentTimeMillis() - startTime));
     }
     catch (SQLException e) {
-      logger.error("Failed: " + (System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+      logQueryError(sql, (System.currentTimeMillis() - startTime), e);
       throw e;
     }
 
@@ -1190,24 +1177,24 @@ public class Database implements StorageObject {
   public int executeUpdate(String sql)
     throws StorageObjectFailure, SQLException {
     int result = -1;
-    long startTime = System.currentTimeMillis();
     Connection con = null;
     PreparedStatement pstmt = null;
 
+    logQueryBefore(sql);
+    long startTime = System.currentTimeMillis();
     try {
       con = obtainConnection();
       pstmt = con.prepareStatement(sql);
       result = pstmt.executeUpdate();
+      logQueryAfter(sql, System.currentTimeMillis() - startTime);
     }
     catch (Throwable e) {
-      logger.error("Database.executeUpdate(" + sql + "): " + e.getMessage());
+      logQueryError(sql, System.currentTimeMillis() - startTime, e);
       throw new StorageObjectFailure("Database.executeUpdate(" + sql + "): " + e.getMessage(), e);
     }
     finally {
       freeConnection(con, pstmt);
     }
-
-    logger.info((System.currentTimeMillis() - startTime) + "ms. for: " + sql);
     return result;
   }
 
@@ -1216,6 +1203,7 @@ public class Database implements StorageObject {
    */
   private void processMetaData(ResultSetMetaData aMetaData) throws StorageObjectFailure {
     fieldNames = new ArrayList();
+    fieldNameToType = new HashMap();
 
     try {
       int numFields = aMetaData.getColumnCount();
@@ -1224,6 +1212,7 @@ public class Database implements StorageObject {
       for (int i = 1; i <= numFields; i++) {
         fieldNames.add(aMetaData.getColumnName(i));
         fieldTypes[i - 1] = aMetaData.getColumnType(i);
+        fieldNameToType.put(aMetaData.getColumnName(i), new Integer(aMetaData.getColumnType(i)));
       }
     }
     catch (SQLException e) {
@@ -1234,7 +1223,7 @@ public class Database implements StorageObject {
   /**
    * Retrieves metadata from the table this Database object represents
    */
-  private void retrieveMetaData() throws StorageObjectFailure {
+  private void acquireMetaData() throws StorageObjectFailure {
     Connection connection = null;
     PreparedStatement statement = null;
     String sql = "select * from " + mainTable + " where 0=1";
@@ -1253,7 +1242,7 @@ public class Database implements StorageObject {
       }
     }
     catch (SQLException e) {
-      throwSQLException(e, "retrieveMetaData");
+      throwSQLException(e, "acquireMetaData");
     }
     finally {
       freeConnection(connection, statement);
@@ -1337,10 +1326,10 @@ public class Database implements StorageObject {
    * Invalidates any cached entity list
    */
   private void invalidateStore() {
-    // invalidating all EntityLists corresponding with theEntityClass
-    if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+    // invalidating all EntityLists corresponding with entityClass
+    if (StoreUtil.extendsStorableEntity(entityClass)) {
       StoreContainerType stoc_type =
-        StoreContainerType.valueOf(theEntityClass, StoreContainerType.STOC_TYPE_ENTITYLIST);
+        StoreContainerType.valueOf(entityClass, StoreContainerType.STOC_TYPE_ENTITYLIST);
       o_store.invalidate(stoc_type);
     }
   }
@@ -1363,8 +1352,14 @@ public class Database implements StorageObject {
 
         if(resultSet!=null) {
           if (resultSet.next()) {
-            inputStream = resultSet.getBlob(1).getBinaryStream();
-            imageInputStream = new BinaryFieldInputStream(inputStream, connection, statement);
+            if (resultSet.getMetaData().getColumnType(1) == java.sql.Types.BINARY) {
+              byte[] data = resultSet.getBytes(1);
+              imageInputStream = new ByteArrayInputStream(data);
+            }
+            else {
+              inputStream = resultSet.getBlob(1).getBinaryStream();
+              imageInputStream = new BinaryFieldInputStream(inputStream, connection, statement);
+            }
           }
           resultSet.close();
         }
@@ -1398,21 +1393,37 @@ public class Database implements StorageObject {
   }
 
   /**
-   * Sets a binary value. The query is supposed to contain 1 ? denoting where the
-   * binary value should be inserted.
-   *
-   * e.g. <code>update images set image_data = ? where id= 22</code>
+   * Sets a binary value for a particular field in a record specified by its identifier
    */
-  public void setBinaryField(String aQuery, byte aData[]) throws StorageObjectFailure, SQLException {
+  public void setBinaryField(String aFieldName, String anObjectId, byte aData[]) throws StorageObjectFailure, SQLException {
     PreparedStatement statement = null;
     Connection connection = obtainConnection();
+
     try {
       connection.setAutoCommit(false);
       try {
-        statement = connection.prepareStatement(aQuery);
-        statement.setBinaryStream(1, new ByteArrayInputStream(aData), aData.length);
-        statement.execute();
-        connection.commit();
+        // are we using bytea ?
+        if (getFieldType(aFieldName) == java.sql.Types.BINARY) {
+          statement = connection.prepareStatement(
+                "update " + mainTable + " set " + aFieldName + " = ? where " + getIdFieldName() + "=" + Integer.parseInt(anObjectId));
+          statement.setBytes(1, aData);
+          statement.execute();
+          connection.commit();
+        }
+        // or the old oid's
+        else {
+          PGConnection postgresqlConnection = (org.postgresql.PGConnection) ((DelegatingConnection) connection).getDelegate();
+          LargeObjectManager lobManager = postgresqlConnection.getLargeObjectAPI();
+          int oid = lobManager.create(LargeObjectManager.READ | LargeObjectManager.WRITE);
+          LargeObject obj = lobManager.open(oid, LargeObjectManager.WRITE);  // Now open the file File file =
+          obj.write(aData);
+          obj.close();
+          statement = connection.prepareStatement(
+                "update " + mainTable + " set " + aFieldName + " = ? where " + getIdFieldName() + "=" + Integer.parseInt(anObjectId));
+          statement.setInt(1, oid);
+          statement.execute();
+          connection.commit();
+        }
       }
       finally {
         connection.setAutoCommit(true);
@@ -1423,6 +1434,28 @@ public class Database implements StorageObject {
     }
   }
 
+  private void logQueryBefore(String aQuery) {
+    logger.debug("about to perform QUERY " + aQuery);
+//    (new Throwable()).printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
+  }
+
+  private void logQueryAfter(String aQuery, long aTime) {
+    logger.info("QUERY " + aQuery + " took " + aTime + "ms.");
+  }
+
+  private void logQueryError(String aQuery, long aTime, Throwable anException) {
+    logger.error("QUERY " + aQuery + " took " + aTime + "ms, but threw exception " + anException.toString());
+  }
+
+  private int getFieldType(String aFieldName) {
+    if (fieldNameToType == null) {
+      acquireMetaData();
+    }
+
+    return ((Integer) fieldNameToType.get(aFieldName)).intValue();
+  }
+
+
   /**
    * a small wrapper class that allows us to store the DB connection resources
    * that the BlobInputStream is using and free them upon closing of the stream