media handling fixes, gotten rid of StorageObject, set the default method for blots...
[mir.git] / source / mir / storage / Database.java
index 452dd98..ea6d987 100755 (executable)
@@ -40,23 +40,25 @@ import mir.storage.store.*;
 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.io.*;
 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.LargeObjectManager;
+import org.postgresql.largeobject.LargeObject;
+
 /**
  * Implements database access.
  *
- * @version $Id: Database.java,v 1.44.2.25 2005/01/09 22:07:45 zapata Exp $
+ * @version $Id: Database.java,v 1.44.2.26 2005/01/23 15:36:03 zapata 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;
@@ -70,6 +72,7 @@ public class Database implements StorageObject {
 
   protected List fieldNames;
   protected int[] fieldTypes;
+  protected Map fieldNameToType;
 
   protected Class entityClass;
   private int defaultLimit;
@@ -108,13 +111,6 @@ 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 entityClass;
   }
@@ -141,12 +137,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;
   }
 
@@ -174,11 +165,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;
@@ -593,10 +584,6 @@ public class Database implements StorageObject {
         theReturnList.setStorage(this);
         theReturnList.setLimit(aLimit);
 
-        if (anOffset >= aLimit) {
-          theReturnList.setPrevBatch(anOffset - aLimit);
-        }
-
         if (hasMore) {
           theReturnList.setNextBatch(anOffset + aLimit);
         }
@@ -951,10 +938,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();
@@ -1027,6 +1010,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;
@@ -1056,6 +1043,10 @@ public class Database implements StorageObject {
     }
   };
 
+  /**
+   * 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);
@@ -1073,6 +1064,10 @@ public class Database implements StorageObject {
     }
   };
 
+  /**
+   * 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);
 
@@ -1189,6 +1184,7 @@ public class Database implements StorageObject {
    */
   private void processMetaData(ResultSetMetaData aMetaData) throws StorageObjectFailure {
     fieldNames = new ArrayList();
+    fieldNameToType = new HashMap();
 
     try {
       int numFields = aMetaData.getColumnCount();
@@ -1197,6 +1193,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) {
@@ -1207,7 +1204,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";
@@ -1226,7 +1223,7 @@ public class Database implements StorageObject {
       }
     }
     catch (SQLException e) {
-      throwSQLException(e, "retrieveMetaData");
+      throwSQLException(e, "acquireMetaData");
     }
     finally {
       freeConnection(connection, statement);
@@ -1336,8 +1333,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();
         }
@@ -1371,21 +1374,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);
@@ -1409,6 +1428,15 @@ public class Database implements StorageObject {
     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