Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbResources.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbResources.java	(revision 0)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbResources.java	(revision 0)
@@ -0,0 +1,57 @@
+package org.apache.jackrabbit.core.data.db;
+
+import java.io.Closeable;
+import java.io.InputStream;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.core.persistence.bundle.util.ConnectionRecoveryManager;
+
+/**
+ * Represents the resources used to back a database-based input stream.
+ */
+public class DbResources implements Closeable {
+	final protected ConnectionRecoveryManager conn;
+	final protected ResultSet rs;
+	final protected Statement stmt;
+	final protected InputStream in;
+	final protected DbDataStore store;
+	protected boolean closed;
+
+	public DbResources(ConnectionRecoveryManager conn, ResultSet rs, Statement stmt, InputStream in, DbDataStore store) {
+		this.conn = conn;
+		this.rs = rs;
+		this.stmt = stmt;
+		this.in = in;
+		this.store = store;
+		this.closed = false;
+	}
+
+	public ConnectionRecoveryManager getConnection() {
+		return conn;
+	}
+
+	public InputStream getInputStream() {
+		return in;
+	}
+
+	public ResultSet getResultSet() {
+		return rs;
+	}
+
+	public Statement getStatement() {
+		return stmt;
+	}
+
+	public void close() {
+		if (!closed) {
+			closed = true;
+			DatabaseHelper.closeSilently(rs);
+			try {
+				store.putBack(conn);
+			}
+			catch (Exception e) {}
+		}
+	}
+}
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbInputStream.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbInputStream.java	(revision 0)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbInputStream.java	(revision 0)
@@ -0,0 +1,200 @@
+/*
+ * 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.jackrabbit.core.data.db;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataStoreException;
+
+/**
+ * This class represents an input stream backed by a database. It allows the stream to be used by
+ * keeping the DB resources open until the stream is closed. When the stream is finished or
+ * close()d, then the resources are freed.
+ */
+public class DbInputStream extends FilterInputStream {
+    protected DbResources resources;
+    protected boolean streamFinished;
+    protected boolean streamClosed;
+    protected DbDataStore store;
+    protected DataIdentifier identifier;
+
+    /**
+     * @param in the stream obtained by a call to ResultSet.getBinaryStream().
+     * @param con the connection to the DB. It must not be closed.
+     * @param rs the result set from wich the stream is obtained. It must not be closed.
+     * @param stmt the statemen that produced the result set. It must not be closed.
+     */
+    protected DbInputStream(DbDataStore store, DataIdentifier identifier) {
+        super(null);
+        streamFinished = false;
+        streamClosed = true;
+        this.store = store;
+        this.identifier = identifier;
+    }
+
+    private void getStream() throws IOException {
+        try {
+            resources = store.getDatabaseResources(identifier);
+            in = resources.getInputStream();
+            streamClosed = false;
+        } catch (DataStoreException e) {
+            IOException e2 = new IOException(e.getMessage());
+            e2.initCause(e);
+            throw e2;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * When the stream is consumed, the database resources held by the instance are closed.
+     */
+    public int read() throws IOException {
+        if (streamFinished) {
+            return -1;
+        }
+        if (in == null) {
+            getStream();
+        }
+        int c = in.read();
+        if (c == -1) {
+            streamFinished = true;
+            close();
+        }
+        return c;
+    }
+
+    /**
+     * {@inheritDoc}
+     * When the stream is consumed, the database resources held by the instance are closed.
+     */
+    public int read(byte b[]) throws IOException {
+        if (streamFinished) {
+            return -1;
+        }
+        int c = read(b, 0, b.length);
+        if (c == -1) {
+            streamFinished = true;
+            close();
+        }
+        return c;
+    }
+
+    /**
+     * {@inheritDoc}
+     * When the stream is consumed, the database resources held by the instance are closed.
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        if (streamFinished) {
+            return -1;
+        }
+        if (in == null) {
+            getStream();
+        }
+        int c = in.read(b, off, len);
+        if (c == -1) {
+            streamFinished = true;
+            close();
+        }
+        return c;
+    }
+
+    /**
+     * {@inheritDoc}
+     * When the stream is consumed, the database resources held by the instance are closed.
+     */
+    public void close() throws IOException {
+        if (!streamClosed) {
+            streamClosed = true;
+            // It may be null (see constructor)
+            if (in != null) {
+                super.close();
+            }
+            // resources may be null (if getStream() was not called)
+            if (resources != null) {
+                resources.close();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public long skip(long n) throws IOException {
+        if (in == null) {
+            getStream();
+        }
+        return in.skip(n);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int available() throws IOException {
+        if (in == null) {
+            getStream();
+        }
+        return in.available();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized void mark(int readlimit) {
+        if (in == null) {
+            try {
+                getStream();
+            } catch (IOException e) {
+            }
+        }
+        in.mark(readlimit);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized void reset() throws IOException {
+        if (in == null) {
+            getStream();
+        }
+        in.reset();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean markSupported() {
+        if (in == null) {
+            try {
+                getStream();
+            } catch (IOException e) {
+                return false;
+            }
+        }
+        return in.markSupported();
+    }
+
+    /**
+     * Last attempt to close the resources.
+     */
+    protected void finalize() {
+        try {
+            close();
+        } catch (IOException e) {
+        }
+    }
+}
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DatabaseHelper.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DatabaseHelper.java	(revision 0)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DatabaseHelper.java	(revision 0)
@@ -0,0 +1,43 @@
+/*
+ * Created on 09/08/2007
+ */
+package org.apache.jackrabbit.core.data.db;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DatabaseHelper {
+    private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class);
+
+    public static void closeSilently(Connection con) {
+        try {
+            if (con != null) {
+                con.close();
+            }
+        } catch (SQLException e) {
+        }
+    }
+
+    public static void closeSilently(ResultSet rs) {
+        try {
+            if (rs != null) {
+                rs.close();
+            }
+        } catch (SQLException e) {
+        }
+    }
+
+    public static void closeSilently(Statement stmt) {
+        try {
+            if (stmt != null) {
+                stmt.close();
+            }
+        } catch (SQLException e) {
+        }
+    }
+}
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java	(revision 632068)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java	(working copy)
@@ -29,6 +29,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -486,7 +487,56 @@
         }
     }
 
-    /**
+	/**
+	 * getDatabaseResources() does NOT close the DB resources on success. It's up to the client
+	 * of the stream backed by these resources to close it and therefore close the DB resources.
+	 */
+	public DbResources getDatabaseResources(DataIdentifier identifier) throws DataStoreException {
+		ConnectionRecoveryManager conn = null;
+		PreparedStatement prep = null;
+		ResultSet rs = null;
+		boolean success = true;
+		DbResources dbResources = null;
+		InputStream result = null;
+		try {
+			conn = getConnection();
+            prep = conn.executeStmt(selectDataSQL, new Object[]{identifier.toString()});
+			rs = prep.getResultSet();
+            if (!rs.next()) {
+                throw new DataStoreException("Record not found: " + identifier);
+            }
+			InputStream stream = rs.getBinaryStream(2);
+			if (stream == null) {
+				// If the stream is null, go ahead and close resources
+				result = new ByteArrayInputStream(new byte[0]);
+				DatabaseHelper.closeSilently(rs);
+				putBack(conn);
+			}
+			else {
+	            result = new BufferedInputStream(stream);
+	            if (copyWhenReading) {
+	                File temp = moveToTempFile(result);
+	                result = new TempFileInputStream(temp);
+	            }
+			}
+			
+			dbResources = new DbResources(conn, rs, prep, result, this);
+			success = true;
+		}
+		catch (Exception e) {
+            success = false;
+			throw convert("Retrieving database resources ", e);
+		}
+		finally {
+			if (!success) {
+				DatabaseHelper.closeSilently(rs);
+				putBack(conn);
+			}
+		}
+		return dbResources;
+	}
+
+	/**
      * {@inheritDoc}
      */
     public synchronized void init(String homeDir) throws DataStoreException {
@@ -646,32 +696,6 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    public InputStream getInputStream(DataIdentifier identifier) throws DataStoreException {
-        ConnectionRecoveryManager conn = getConnection();
-        try {
-            String id = identifier.toString();
-            // SELECT ID, DATA FROM DATASTORE WHERE ID = ?
-            PreparedStatement prep = conn.executeStmt(selectDataSQL, new Object[]{id});
-            ResultSet rs = prep.getResultSet();
-            if (!rs.next()) {
-                throw new DataStoreException("Record not found: " + identifier);
-            }
-            InputStream in = new BufferedInputStream(rs.getBinaryStream(2));
-            if (copyWhenReading) {
-                File temp = moveToTempFile(in);
-                in = new TempFileInputStream(temp);
-            }
-            return in;
-        } catch (Exception e) {
-            throw convert("Can not read identifier " + identifier, e);
-        } finally {
-            putBack(conn);
-        }
-    }
-
-    /**
      * Get the database type (if set).
      * @return the database type
      */
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java	(revision 632068)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java	(working copy)
@@ -33,7 +33,7 @@
 
     /**
      * Creates a data record based on the given identifier and length.
-     *
+     * 
      * @param identifier data identifier
      * @param length the length
      * @param file file that contains the binary stream
@@ -58,7 +58,10 @@
      */
     public InputStream getStream() throws DataStoreException {
         lastModified = store.touch(getIdentifier(), lastModified);
-        return store.getInputStream(getIdentifier());
+        return new DbInputStream(store, getIdentifier());
     }
 
+    public long getLastModified() {
+        return lastModified;
+    }
 }
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java	(revision 632068)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/DataRecord.java	(working copy)
@@ -46,4 +46,8 @@
      */
     InputStream getStream() throws DataStoreException;
 
+    /**
+     * Returns the last modified of the record.
+     */
+    public long getLastModified();
 }
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java	(revision 632068)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/FileDataRecord.java	(working copy)
@@ -37,7 +37,7 @@
      * @param identifier data identifier
      * @param file file that contains the binary stream
      */
-    protected FileDataRecord(DataIdentifier identifier, File file) {
+    public FileDataRecord(DataIdentifier identifier, File file) {
         super(identifier);
         assert file.isFile();
         this.file = file;
@@ -61,4 +61,7 @@
         }
     }
 
+    public long getLastModified() {
+    	return file.lastModified();
+    }
 }
