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(this.conn);
+	}
+
+	public InputStream getInputStream() {
+		return(this.in);
+	}
+
+	public ResultSet getResultSet() {
+		return(this.rs);
+	}
+
+	public Statement getStatement() {
+		return(this.stmt);
+	}
+
+	public void close() {
+		if (!this.closed) {
+			this.closed = true;
+			DatabaseHelper.close(this.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,153 @@
+/*
+ * Created on 08/08/2007
+ */
+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);
+		this.streamFinished = false;
+		this.streamClosed = true;
+		this.store = store;
+		this.identifier = identifier;
+	}
+
+	private void getStream() throws IOException {
+		try {
+			this.resources = store.getDatabaseResources(identifier);
+			this.in = resources.getInputStream();
+			this.streamClosed = false;
+		}
+		catch (DataStoreException e) {
+			throw new IOException(e.getMessage());
+		}
+	}
+
+	public int read() throws IOException {
+		if (this.streamFinished) {
+			return(-1);
+		}
+		if (in == null) {
+			getStream();
+		}
+		int c = in.read();
+		if (c == -1) {
+			this.streamFinished = true;
+			close();
+		}
+		return(c);
+	}
+
+	public int read(byte b[]) throws IOException {
+		if (this.streamFinished) {
+			return(-1);
+		}
+		int c = read(b, 0, b.length);
+		if (c == -1) {
+			this.streamFinished = true;
+			close();
+		}
+		return(c);
+	}
+
+	public int read(byte b[], int off, int len) throws IOException {
+		if (this.streamFinished) {
+			return(-1);
+		}
+		if (in == null) {
+			getStream();
+		}
+		int c = in.read(b, off, len);
+		if (c == -1) {
+			this.streamFinished = true;
+			close();
+		}
+		return(c);
+	}
+
+	public void close() throws IOException {
+		if (!this.streamClosed) {
+			this.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();
+			}
+		}
+	}
+
+	public long skip(long n) throws IOException {
+		if (in == null) {
+			getStream();
+		}
+		return(in.skip(n));
+	}
+
+	public int available() throws IOException {
+		if (in == null) {
+			getStream();
+		}
+		return(in.available());
+	}
+
+	public synchronized void mark(int readlimit) {
+		if (in == null) {
+			try {
+				getStream();
+			}
+			catch (IOException e) {}
+		}
+		in.mark(readlimit);
+	}
+
+	public synchronized void reset() throws IOException {
+		if (in == null) {
+			getStream();
+		}
+		in.reset();
+	}
+
+	public boolean markSupported() {
+		if (in == null) {
+			try {
+				getStream();
+			}
+			catch (IOException e) {
+				return(false);
+			}
+		}
+		return(in.markSupported());
+	}
+
+	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,78 @@
+/*
+ * Created on 09/08/2007
+ */
+package org.apache.jackrabbit.core.data.db;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.text.MessageFormat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DatabaseHelper {
+	private static Logger log = LoggerFactory.getLogger(DatabaseHelper.class);
+
+	public static String prepareSchemaObjectPrefix(String schemaObjectPrefix, String extraNameCharacters) {
+		extraNameCharacters += "ABCDEFGHIJKLMNOPQRSTUVWXZY0123456789_";
+
+		String prefix = schemaObjectPrefix.toUpperCase();
+		StringBuffer escaped = new StringBuffer();
+		for (int i = 0; i < prefix.length(); i++) {
+			char c = prefix.charAt(i);
+			if (extraNameCharacters.indexOf(c) == -1) {
+				escaped.append('_');
+			}
+			else {
+				escaped.append(c);
+			}
+		}
+		return(escaped.toString());
+	}
+
+	private  static BufferedReader getResourceAsReader(String resourceName) {
+		BufferedReader reader;
+		// get create schema script from class path resource
+		InputStream in = DatabaseHelper.class.getResourceAsStream(resourceName);
+		if (in == null) {
+			MessageFormat fmt = new MessageFormat("Unable to load database script resource '{0}'.");
+			String msg = fmt.format(resourceName);
+			log.debug(msg);
+			throw new IllegalArgumentException(msg);
+		}
+
+		reader = new BufferedReader(new InputStreamReader(in));
+		return(reader);
+	}
+
+	public static void close(Connection con) {
+		try {
+			if (con != null) {
+				con.close();
+			}
+		}
+		catch (SQLException e) {}
+	}
+
+	public static void close(ResultSet rs) {
+		try {
+			if (rs != null) {
+				rs.close();
+			}
+		}
+		catch (SQLException e) {}
+	}
+
+	public static void close(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 614607)
+++ 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;
@@ -471,7 +472,55 @@
         }
     }
 
-    /**
+	/**
+	 * 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.close(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) {
+			throw convert("Retrieving database resources ", e);
+		}
+		finally {
+			if (!success) {
+				DatabaseHelper.close(rs);
+				putBack(conn);
+			}
+		}
+		return(dbResources);
+	}
+
+	/**
      * {@inheritDoc}
      */
     public synchronized void init(String homeDir) throws DataStoreException {
@@ -622,32 +671,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 614607)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataRecord.java	(working copy)
@@ -57,8 +57,12 @@
      * {@inheritDoc}
      */
     public InputStream getStream() throws DataStoreException {
-        lastModified = store.touch(getIdentifier(), lastModified);
-        return store.getInputStream(getIdentifier());
+//        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 614607)
+++ 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 614607)
+++ 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();
+    }
 }
