OPENJPA-477 Making StoreManager more flexible and extensible

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@614763 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Catalina Wei 2008-01-24 01:33:48 +00:00
parent 8d18daabd7
commit a8f6d3c116
19 changed files with 499 additions and 138 deletions

View File

@ -181,7 +181,7 @@ public abstract class AbstractUpdateManager
/**
* Recursive method to insert the given instance, base class first.
*/
private void insert(OpenJPAStateManager sm, ClassMapping mapping,
protected void insert(OpenJPAStateManager sm, ClassMapping mapping,
RowManager rowMgr, JDBCStore store, Collection customs)
throws SQLException {
Boolean custom = mapping.isCustomInsert(sm, store);
@ -228,7 +228,7 @@ public abstract class AbstractUpdateManager
/**
* Recursive method to delete the given instance, base class last.
*/
private void delete(OpenJPAStateManager sm, ClassMapping mapping,
protected void delete(OpenJPAStateManager sm, ClassMapping mapping,
RowManager rowMgr, JDBCStore store, Collection customs)
throws SQLException {
Boolean custom = mapping.isCustomDelete(sm, store);
@ -271,7 +271,7 @@ public abstract class AbstractUpdateManager
/**
* Recursive method to update the given instance.
*/
private void update(OpenJPAStateManager sm, BitSet dirty,
protected void update(OpenJPAStateManager sm, BitSet dirty,
ClassMapping mapping, RowManager rowMgr, JDBCStore store,
Collection customs) throws SQLException {
Boolean custom = mapping.isCustomUpdate(sm, store);
@ -300,7 +300,7 @@ public abstract class AbstractUpdateManager
/**
* Update version and discriminator indicators.
*/
private void updateIndicators(OpenJPAStateManager sm, ClassMapping mapping,
protected void updateIndicators(OpenJPAStateManager sm, ClassMapping mapping,
RowManager rowMgr, JDBCStore store, Collection customs,
boolean versionUpdateOnly) throws SQLException {
while (mapping.getJoinablePCSuperclassMapping() != null)

View File

@ -140,7 +140,7 @@ public class JDBCBrokerFactory
/**
* Synchronize the mappings of the classes listed in the configuration.
*/
private void synchronizeMappings(ClassLoader loader) {
protected void synchronizeMappings(ClassLoader loader) {
JDBCConfiguration conf = (JDBCConfiguration) getConfiguration();
String action = conf.getSynchronizeMappings();
if (StringUtils.isEmpty(action))

View File

@ -272,7 +272,7 @@ public class JDBCStoreManager
/**
* Initialize a newly-loaded instance.
*/
private boolean initializeState(OpenJPAStateManager sm, PCState state,
protected boolean initializeState(OpenJPAStateManager sm, PCState state,
JDBCFetchConfiguration fetch, ConnectionInfo info)
throws ClassNotFoundException, SQLException {
Object oid = sm.getObjectId();
@ -294,7 +294,7 @@ public class JDBCStoreManager
Select.SUBS_EXACT);
if (res == null && !selectPrimaryKey(sm, mapping, fetch))
return false;
if (res != null && !res.next())
if (isEmptyResult(res))
return false;
} else {
ClassMapping[] mappings = mapping.
@ -311,16 +311,14 @@ public class JDBCStoreManager
} else
res = getInitializeStateUnionResult(sm, mapping, mappings,
fetch);
if (res != null && !res.next())
if (isEmptyResult(res))
return false;
}
// figure out what type of object this is; the state manager
// only guarantees to provide a base class
Class type;
if (res == null)
type = mapping.getDescribedType();
else {
if ((type = getType(res, mapping)) == null) {
if (res.getBaseMapping() != null)
mapping = res.getBaseMapping();
res.startDataRequest(mapping.getDiscriminator());
@ -342,7 +340,7 @@ public class JDBCStoreManager
// re-get the mapping in case the instance was a subclass
mapping = (ClassMapping) sm.getMetaData();
load(mapping, sm, fetch, res);
mapping.getVersion().afterLoad(sm, this);
getVersion(mapping, sm, res);
}
return true;
} finally {
@ -350,6 +348,35 @@ public class JDBCStoreManager
res.close();
}
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of getting version from the result set.
*/
protected void getVersion(ClassMapping mapping, OpenJPAStateManager sm,
Result res) throws SQLException {
mapping.getVersion().afterLoad(sm, this);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of checking whether the result set is empty or not.
*/
protected boolean isEmptyResult(Result res) throws SQLException {
if (res != null && !res.next())
return true;
return false;
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of getting type from the result set.
*/
protected Class getType(Result res, ClassMapping mapping){
if (res == null)
return mapping.getDescribedType();
return null;
}
/**
* Allow the mapping to custom load data. Return null if the mapping
@ -427,7 +454,7 @@ public class JDBCStoreManager
sel.wherePrimaryKey(sm.getObjectId(), base, this);
Result exists = sel.execute(this, fetch);
try {
if (!exists.next())
if (isEmptyResult(exists))
return false;
// record locked?
@ -478,7 +505,7 @@ public class JDBCStoreManager
sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
res = sel.execute(this, jfetch, lockLevel);
try {
if (!res.next())
if (isEmptyResult(res))
return false;
load(mapping, sm, jfetch, res);
} finally {

View File

@ -499,11 +499,11 @@ public class JDBCStoreQuery
for (int i = 0; i < sql.length; i++) {
stmnt = null;
try {
stmnt = sql[i].prepareStatement(conn);
count += stmnt.executeUpdate();
stmnt = prepareStatement(conn, sql[i]);
count += executeUpdate(conn, stmnt, sql[i], isUpdate);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, sql[i].getSQL(),
_store.getDBDictionary());
_store.getDBDictionary());
} finally {
if (stmnt != null)
try { stmnt.close(); } catch (SQLException se) {}
@ -649,4 +649,22 @@ public class JDBCStoreQuery
sql[i] = ((Select) sels.get(i)).toSelect(false, fetch).getSQL(true);
return sql;
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing update.
*/
protected int executeUpdate(Connection conn, PreparedStatement stmnt,
SQLBuffer sqlBuf, boolean isUpdate) throws SQLException {
return stmnt.executeUpdate();
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing statement.
*/
protected PreparedStatement prepareStatement(Connection conn, SQLBuffer sql)
throws SQLException {
return sql.prepareStatement(conn);
}
}

View File

@ -132,18 +132,10 @@ public class PessimisticLockManager
PreparedStatement stmnt = null;
ResultSet rs = null;
try {
stmnt = sql.prepareStatement(conn);
if (timeout >= 0 && dict.supportsQueryTimeout) {
if (timeout < 1000) {
timeout = 1000;
if (log.isWarnEnabled())
log.warn(_loc.get("millis-query-timeout"));
}
stmnt.setQueryTimeout(timeout / 1000);
}
rs = stmnt.executeQuery();
if (!rs.next())
throw new LockException(sm.getManagedInstance());
stmnt = prepareStatement(conn, sql);
setTimeout(stmnt, timeout);
rs = executeQuery(conn, stmnt, sql);
checkLock(rs, sm);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, dict);
} finally {
@ -168,4 +160,54 @@ public class PessimisticLockManager
log.info(_loc.get("start-trans-for-lock"));
}
}
public JDBCStore getStore() {
return _store;
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing statement.
*/
protected PreparedStatement prepareStatement(Connection conn, SQLBuffer sql)
throws SQLException {
return sql.prepareStatement(conn);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of setting query timeout.
*/
protected void setTimeout(PreparedStatement stmnt, int timeout)
throws SQLException {
DBDictionary dict = _store.getDBDictionary();
if (timeout >= 0 && dict.supportsQueryTimeout) {
if (timeout < 1000) {
timeout = 1000;
if (log.isWarnEnabled())
log.warn(_loc.get("millis-query-timeout"));
}
stmnt.setQueryTimeout(timeout / 1000);
}
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing query.
*/
protected ResultSet executeQuery(Connection conn, PreparedStatement stmnt,
SQLBuffer sql) throws SQLException {
return stmnt.executeQuery();
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of checking lock from the result set.
*/
protected void checkLock(ResultSet rs, OpenJPAStateManager sm)
throws SQLException {
if (!rs.next())
throw new LockException(sm.getManagedInstance());
return;
}
}

View File

@ -35,7 +35,6 @@ import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.util.ApplicationIds;
import org.apache.openjpa.util.OpenJPAException;
import org.apache.openjpa.util.OptimisticException;
import org.apache.openjpa.meta.ClassMetaData;
/**
* Basic prepared statement manager implementation.
@ -89,12 +88,13 @@ public class PreparedStatementManagerImpl
// prepare statement
String sql = row.getSQL(_dict);
PreparedStatement stmnt = _conn.prepareStatement(sql);
PreparedStatement stmnt = prepareStatement(sql);
// setup parameters and execute statement
row.flush(stmnt, _dict, _store);
if (stmnt != null)
row.flush(stmnt, _dict, _store);
try {
int count = stmnt.executeUpdate();
int count = executeUpdate(stmnt, sql, row);
if (count != 1) {
Object failed = row.getFailedObject();
if (failed != null)
@ -107,7 +107,8 @@ public class PreparedStatementManagerImpl
} catch (SQLException se) {
throw SQLExceptions.getStore(se, row.getFailedObject(), _dict);
} finally {
try { stmnt.close(); } catch (SQLException se) {}
if (stmnt != null)
try { stmnt.close(); } catch (SQLException se) {}
}
// set auto assign values
@ -128,4 +129,22 @@ public class PreparedStatementManagerImpl
public void flush() {
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing update.
*/
protected int executeUpdate(PreparedStatement stmnt, String sql,
RowImpl row) throws SQLException {
return stmnt.executeUpdate();
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing statement.
*/
protected PreparedStatement prepareStatement(String sql)
throws SQLException {
return _conn.prepareStatement(sql);
}
}

View File

@ -23,6 +23,7 @@ import java.io.StreamTokenizer;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
@ -157,7 +158,7 @@ public class SQLStoreQuery
/**
* Executes the filter as a SQL query.
*/
private static class SQLExecutor
protected static class SQLExecutor
extends AbstractExecutor {
private final ClassMetaData _meta;
@ -224,20 +225,14 @@ public class SQLStoreQuery
PreparedStatement stmnt = null;
try {
stmnt = buf.prepareCall(conn);
stmnt = prepareCall(conn, buf);
int index = 0;
for (Iterator i = paramList.iterator(); i.hasNext();)
for (Iterator i = paramList.iterator(); i.hasNext() &&
stmnt != null;)
dict.setUnknown(stmnt, ++index, i.next(), null);
int count = 0;
if (_call && stmnt.execute() == false) {
count = stmnt.getUpdateCount();
}
else {
// native insert, update, delete
count = stmnt.executeUpdate();
}
int count = executeUpdate(store, conn, stmnt, buf);
return Numbers.valueOf(count);
} catch (SQLException se) {
if (stmnt != null)
@ -276,20 +271,23 @@ public class SQLStoreQuery
try {
// use the right method depending on sel vs. proc, lrs setting
if (_select && !range.lrs)
stmnt = buf.prepareStatement(conn);
stmnt = prepareStatement(conn, buf);
else if (_select)
stmnt = buf.prepareStatement(conn, fetch, -1, -1);
stmnt = prepareStatement(conn, buf, fetch, -1, -1);
else if (!range.lrs)
stmnt = buf.prepareCall(conn);
stmnt = prepareCall(conn, buf);
else
stmnt = buf.prepareCall(conn, fetch, -1, -1);
stmnt = prepareCall(conn, buf, fetch, -1, -1);
int index = 0;
for (Iterator i = paramList.iterator(); i.hasNext();)
for (Iterator i = paramList.iterator(); i.hasNext() &&
stmnt != null;)
dict.setUnknown(stmnt, ++index, i.next(), null);
ResultSetResult res = new ResultSetResult(conn, stmnt,
stmnt.executeQuery(), store);
ResultSet rs = executeQuery(store, conn, stmnt, buf, paramList);
ResultSetResult res = stmnt != null ?
new ResultSetResult(conn, stmnt, rs, store) :
new ResultSetResult(conn, rs, dict);
if (_resultMapping != null)
rop = new MappedQueryResultObjectProvider(_resultMapping,
store, fetch, res);
@ -319,5 +317,71 @@ public class SQLStoreQuery
public boolean isPacking(StoreQuery q) {
return q.getContext().getCandidateType() == null;
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing call statement.
*/
protected PreparedStatement prepareCall(Connection conn, SQLBuffer buf)
throws SQLException {
return buf.prepareCall(conn);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing update.
*/
protected int executeUpdate(JDBCStore store, Connection conn,
PreparedStatement stmnt, SQLBuffer buf)
throws SQLException {
int count = 0;
if (_call && stmnt.execute() == false) {
count = stmnt.getUpdateCount();
}
else {
// native insert, update, delete
count = stmnt.executeUpdate();
}
return count;
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing call statement.
*/
protected PreparedStatement prepareCall(Connection conn, SQLBuffer buf,
JDBCFetchConfiguration fetch, int rsType, int rsConcur)
throws SQLException {
return buf.prepareCall(conn, fetch, rsType, rsConcur);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing statement.
*/
protected PreparedStatement prepareStatement(Connection conn,
SQLBuffer buf) throws SQLException {
return buf.prepareStatement(conn);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing statement.
*/
protected PreparedStatement prepareStatement(Connection conn,
SQLBuffer buf, JDBCFetchConfiguration fetch, int rsType,
int rsConcur) throws SQLException {
return buf.prepareStatement(conn, fetch, rsType, rsConcur);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing query.
*/
protected ResultSet executeQuery(JDBCStore store, Connection conn,
PreparedStatement stmnt, SQLBuffer buf, List paramList)
throws SQLException {
return stmnt.executeQuery();
}
}
}

View File

@ -30,7 +30,6 @@ import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.Index;
import org.apache.openjpa.jdbc.schema.PrimaryKey;
import org.apache.openjpa.jdbc.schema.Schema;
import org.apache.openjpa.jdbc.schema.SchemaGroup;
@ -38,6 +37,7 @@ import org.apache.openjpa.jdbc.schema.SchemaTool;
import org.apache.openjpa.jdbc.schema.Schemas;
import org.apache.openjpa.jdbc.schema.Table;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.RowImpl;
import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.SQLExceptions;
import org.apache.openjpa.lib.conf.Configurable;
@ -431,8 +431,8 @@ public class TableJDBCSeq
PreparedStatement stmnt = null;
try {
stmnt = insert.prepareStatement(conn);
stmnt.executeUpdate();
stmnt = prepareStatement(conn, insert);
executeUpdate(_conf, conn, stmnt, insert, RowImpl.ACTION_INSERT);
} finally {
if (stmnt != null)
try { stmnt.close(); } catch (SQLException se) {}
@ -464,17 +464,16 @@ public class TableJDBCSeq
null, false, dict.supportsSelectForUpdate, 0, Long.MAX_VALUE,
false, true);
PreparedStatement stmnt = select.prepareStatement(conn);
PreparedStatement stmnt = prepareStatement(conn, select);
ResultSet rs = null;
try {
rs = stmnt.executeQuery();
if (!rs.next())
return -1;
return dict.getLong(rs, 1);
rs = executeQuery(_conf, conn, stmnt, select);
return getSequence(rs, dict);
} finally {
if (rs != null)
try { rs.close(); } catch (SQLException se) {}
try { stmnt.close(); } catch (SQLException se) {}
if (stmnt != null)
try { stmnt.close(); } catch (SQLException se) {}
}
}
@ -522,8 +521,8 @@ public class TableJDBCSeq
append(_seqColumn).append(" = ").
appendValue(Numbers.valueOf(cur), _seqColumn);
stmnt = upd.prepareStatement(conn);
updates = stmnt.executeUpdate();
stmnt = prepareStatement(conn, upd);
updates = executeUpdate(_conf, conn, stmnt, upd, RowImpl.ACTION_UPDATE);
} finally {
if (rs != null)
try { rs.close(); } catch (SQLException se) {}
@ -704,4 +703,41 @@ public class TableJDBCSeq
public long seq = 1L;
public long max = 0L;
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing statement.
*/
protected PreparedStatement prepareStatement(Connection conn, SQLBuffer buf)
throws SQLException {
return buf.prepareStatement(conn);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing update.
*/
protected int executeUpdate(JDBCConfiguration conf, Connection conn,
PreparedStatement stmnt, SQLBuffer buf, int opcode) throws SQLException {
return stmnt.executeUpdate();
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing query.
*/
protected ResultSet executeQuery(JDBCConfiguration conf, Connection conn,
PreparedStatement stmnt, SQLBuffer buf) throws SQLException {
return stmnt.executeQuery();
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of getting sequence from the result set.
*/
protected long getSequence(ResultSet rs, DBDictionary dict) throws SQLException {
if (rs == null || !rs.next())
return -1;
return dict.getLong(rs, 1);
}
}

View File

@ -49,7 +49,7 @@ import org.apache.openjpa.util.UserException;
*
* @author Abe White
*/
class PCPath
public class PCPath
extends AbstractVal
implements JDBCPath {
@ -549,7 +549,7 @@ class PCPath
/**
* Expression state.
*/
private static class PathExpState
public static class PathExpState
extends ExpState {
public FieldMapping field = null;

View File

@ -93,7 +93,7 @@ public class Param
/**
* Expression state.
*/
private static class ParamExpState
public static class ParamExpState
extends ConstExpState {
public Object sqlValue = null;

View File

@ -87,7 +87,6 @@ import org.apache.openjpa.jdbc.schema.Unique;
import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.exps.Path;
import org.apache.openjpa.kernel.exps.Literal;
import org.apache.openjpa.lib.conf.Configurable;
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.lib.jdbc.ConnectionDecorator;
@ -1982,7 +1981,7 @@ public class DBDictionary
ExpState state = val.initialize(sel, ctx, 0);
// JDBC Paths are always PCPaths; PCPath implements Val
ExpState pathState = ((Val) path).initialize(sel, ctx, 0);
val.calculateValue(sel, ctx, state, (Val) path, pathState);
calculateValue(val, sel, ctx, state, path, pathState);
// append the value with a null for the Select; i
// indicates that the
@ -3476,7 +3475,7 @@ public class DBDictionary
if (str == null)
return new Sequence[0];
PreparedStatement stmnt = conn.prepareStatement(str);
PreparedStatement stmnt = prepareStatement(conn, str);
ResultSet rs = null;
try {
int idx = 1;
@ -3485,21 +3484,19 @@ public class DBDictionary
if (sequenceName != null)
stmnt.setString(idx++, sequenceName);
rs = stmnt.executeQuery();
List seqList = new ArrayList();
while (rs.next())
seqList.add(newSequence(rs));
return (Sequence[]) seqList.toArray(new Sequence[seqList.size()]);
} finally {
rs = executeQuery(conn, stmnt, str);
return getSequence(rs);
} finally {
if (rs != null)
try {
rs.close();
} catch (SQLException se) {
}
try {
stmnt.close();
} catch (SQLException se) {
}
if (stmnt != null)
try {
stmnt.close();
} catch (SQLException se) {
}
}
}
@ -3880,20 +3877,16 @@ public class DBDictionary
});
}
PreparedStatement stmnt = conn.prepareStatement(query);
PreparedStatement stmnt = prepareStatement(conn, query);
ResultSet rs = null;
try {
rs = stmnt.executeQuery();
if (!rs.next())
throw new StoreException(_loc.get("no-genkey"));
Object key = rs.getObject(1);
if (key == null)
log.warn(_loc.get("invalid-genkey", col));
return key;
rs = executeQuery(conn, stmnt, query);
return getKey(rs, col);
} finally {
if (rs != null)
try { rs.close(); } catch (SQLException se) {}
try { stmnt.close(); } catch (SQLException se) {}
if (stmnt != null)
try { stmnt.close(); } catch (SQLException se) {}
}
}
@ -4277,4 +4270,55 @@ public class DBDictionary
OpenJPAStateManager sm, ClassMapping cmd ) {
return disableBatch;
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing query.
*/
protected ResultSet executeQuery(Connection conn, PreparedStatement stmnt, String sql
) throws SQLException {
return stmnt.executeQuery();
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing statement.
*/
protected PreparedStatement prepareStatement(Connection conn, String sql)
throws SQLException {
return conn.prepareStatement(sql);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of getting sequence from the result set.
*/
protected Sequence[] getSequence(ResultSet rs) throws SQLException {
List seqList = new ArrayList();
while (rs != null && rs.next())
seqList.add(newSequence(rs));
return (Sequence[]) seqList.toArray(new Sequence[seqList.size()]);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of getting key from the result set.
*/
protected Object getKey (ResultSet rs, Column col) throws SQLException {
if (!rs.next())
throw new StoreException(_loc.get("no-genkey"));
Object key = rs.getObject(1);
if (key == null)
log.warn(_loc.get("invalid-genkey", col));
return key;
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of calculating value.
*/
protected void calculateValue(Val val, Select sel, ExpContext ctx,
ExpState state, Path path, ExpState pathState) {
val.calculateValue(sel, ctx, state, (Val) path, pathState);
}
}

View File

@ -91,6 +91,17 @@ public class ResultSetResult
setStore(store);
}
/**
* Constructor.
*/
public ResultSetResult(Connection conn,
ResultSet rs, DBDictionary dict) {
_conn = conn;
_stmnt = null;
_rs = rs;
_dict = dict;
}
/**
* JDBC 2 constructor. Relies on being able to retrieve the statement
* from the result set, and the connection from the statement.

View File

@ -20,7 +20,6 @@ package org.apache.openjpa.jdbc.sql;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Array;
@ -57,10 +56,10 @@ import serp.util.Numbers;
public class RowImpl
implements Row, Cloneable {
protected static final Object NULL = new Object();
public static final Object NULL = new Object();
protected static final int VALID = 2 << 0;
private static final int RAW = Integer.MIN_VALUE;
public static final int RAW = Integer.MIN_VALUE;
protected byte flags = 0;
private final Column[] _cols;
@ -950,4 +949,12 @@ public class RowImpl
if (isValid())
row.setValid(true);
}
public Object[] getVals() {
return _vals;
}
public int[] getTypes() {
return _types;
}
}

View File

@ -641,4 +641,12 @@ public final class SQLBuffer
return sub;
}
}
public void setParameters(List params) {
_params = params;
}
public List getColumns() {
return _cols;
}
}

View File

@ -297,10 +297,11 @@ public class SelectImpl
try {
SQLBuffer sql = toSelectCount();
conn = store.getConnection();
stmnt = sql.prepareStatement(conn);
rs = stmnt.executeQuery();
rs.next();
return rs.getInt(1);
stmnt = prepareStatement(conn, sql, null,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, false);
rs = executeQuery(conn, stmnt, sql, false, store);
return getCount(rs);
} finally {
if (rs != null)
try { rs.close(); } catch (SQLException se) {}
@ -342,31 +343,21 @@ public class SelectImpl
}
SQLBuffer sql = toSelect(forUpdate, fetch);
int rsType = (isLRS() && supportsRandomAccess(forUpdate))
boolean isLRS = isLRS();
int rsType = (isLRS && supportsRandomAccess(forUpdate))
? -1 : ResultSet.TYPE_FORWARD_ONLY;
Connection conn = store.getConnection();
PreparedStatement stmnt = null;
ResultSet rs = null;
try {
if (isLRS())
stmnt = sql.prepareStatement(conn, fetch, rsType, -1);
if (isLRS)
stmnt = prepareStatement(conn, sql, fetch, rsType, -1, true);
else
stmnt = sql.prepareStatement(conn, rsType, -1);
// if this is a locking select and the lock timeout is greater than
// the configured query timeout, use the lock timeout
if (forUpdate && _dict.supportsQueryTimeout && fetch != null
&& fetch.getLockTimeout() > stmnt.getQueryTimeout() * 1000) {
int timeout = fetch.getLockTimeout();
if (timeout < 1000) {
timeout = 1000;
Log log = _conf.getLog(JDBCConfiguration.LOG_JDBC);
if (log.isWarnEnabled())
log.warn(_loc.get("millis-query-timeout"));
}
stmnt.setQueryTimeout(timeout / 1000);
}
rs = stmnt.executeQuery();
stmnt = prepareStatement(conn, sql, null, rsType, -1, false);
setTimeout(stmnt, forUpdate, fetch);
rs = executeQuery(conn, stmnt, sql, isLRS, store);
} catch (SQLException se) {
// clean up statement
if (stmnt != null)
@ -375,17 +366,8 @@ public class SelectImpl
throw se;
}
SelectResult res = new SelectResult(conn, stmnt, rs, _dict);
res.setSelect(this);
res.setStore(store);
res.setLocking(forUpdate);
try {
addEagerResults(res, this, store, fetch);
} catch (SQLException se) {
res.close();
throw se;
}
return res;
return getEagerResult(conn, stmnt, rs, store, fetch, forUpdate,
sql.getSQL());
}
/**
@ -423,6 +405,80 @@ public class SelectImpl
}
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of preparing statement.
*/
protected PreparedStatement prepareStatement(Connection conn,
SQLBuffer sql, JDBCFetchConfiguration fetch, int rsType,
int rsConcur, boolean isLRS) throws SQLException {
if (fetch == null)
return sql.prepareStatement(conn, rsType, rsConcur);
else
return sql.prepareStatement(conn, fetch, rsType, -1);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of setting query timeout.
*/
protected void setTimeout(PreparedStatement stmnt, boolean forUpdate,
JDBCFetchConfiguration fetch) throws SQLException {
// if this is a locking select and the lock timeout is greater than
// the configured query timeout, use the lock timeout
if (forUpdate && _dict.supportsQueryTimeout && fetch != null
&& fetch.getLockTimeout() > stmnt.getQueryTimeout() * 1000) {
int timeout = fetch.getLockTimeout();
if (timeout < 1000) {
timeout = 1000;
Log log = _conf.getLog(JDBCConfiguration.LOG_JDBC);
if (log.isWarnEnabled())
log.warn(_loc.get("millis-query-timeout"));
}
stmnt.setQueryTimeout(timeout / 1000);
}
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing query.
*/
protected ResultSet executeQuery(Connection conn, PreparedStatement stmnt,
SQLBuffer sql, boolean isLRS, JDBCStore store) throws SQLException {
return stmnt.executeQuery();
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of getting count from the result set.
*/
protected int getCount(ResultSet rs) throws SQLException {
rs.next();
return rs.getInt(1);
}
/**
* This method is to provide override for non-JDBC or JDBC-like
* implementation of executing eager selects.
*/
protected Result getEagerResult(Connection conn,
PreparedStatement stmnt, ResultSet rs, JDBCStore store,
JDBCFetchConfiguration fetch, boolean forUpdate, String sqlStr)
throws SQLException {
SelectResult res = new SelectResult(conn, stmnt, rs, _dict);
res.setSelect(this);
res.setStore(store);
res.setLocking(forUpdate);
try {
addEagerResults(res, this, store, fetch);
} catch (SQLException se) {
res.close();
throw se;
}
return res;
}
/////////////////////////
// Select implementation
/////////////////////////

View File

@ -39,7 +39,7 @@ import org.apache.openjpa.util.UserException;
*/
public class Bootstrap {
private static final Class[] FACTORY_ARGS =
protected static final Class[] FACTORY_ARGS =
new Class[]{ ConfigurationProvider.class };
private static Localizer s_loc = Localizer.forPackage(Bootstrap.class);
@ -124,7 +124,7 @@ public class Bootstrap {
return (BrokerFactory) meth.invoke(null, new Object[]{ conf });
}
private static String getFactoryClassName(ConfigurationProvider conf,
protected static String getFactoryClassName(ConfigurationProvider conf,
ClassLoader loader) {
try {
return getFactoryClass(conf, loader).getName();

View File

@ -2420,10 +2420,7 @@ public class BrokerImpl
}
// make sure we don't already have the instance cached
StateManagerImpl other = getStateManagerImplById(id, false);
if (other != null && !other.isDeleted() && !other.isNew())
throw new ObjectExistsException(_loc.get("cache-exists",
obj.getClass().getName(), id)).setFailedObject(obj);
checkForDuplicateId(id, obj);
// if had embedded sm, null it
if (sm != null)
@ -3817,7 +3814,7 @@ public class BrokerImpl
_cache.remove(id, sm);
break;
case STATUS_OID_ASSIGN:
_cache.assignObjectId(id, sm);
assignObjectId(_cache, id, sm);
break;
case STATUS_COMMIT_NEW:
_cache.commitNew(id, sm);
@ -4700,4 +4697,23 @@ public class BrokerImpl
};
}
}
/**
* Assign the object id to the cache. Exception will be
* thrown if the id already exists in the cache.
*/
protected void assignObjectId(Object cache, Object id,
StateManagerImpl sm) {
((ManagedCache) cache).assignObjectId(id, sm);
}
/**
* This method makes sure we don't already have the instance cached
*/
protected void checkForDuplicateId(Object id, Object obj) {
StateManagerImpl other = getStateManagerImplById(id, false);
if (other != null && !other.isDeleted() && !other.isNew())
throw new ObjectExistsException(_loc.get("cache-exists",
obj.getClass().getName(), id)).setFailedObject(obj);
}
}

View File

@ -3001,7 +3001,7 @@ public class StateManagerImpl
/**
* Mark the field as loaded or unloaded.
*/
private void setLoaded(int field, boolean isLoaded) {
public void setLoaded(int field, boolean isLoaded) {
// don't continue if loaded state is already correct; otherwise we
// can end up clearing _fieldImpl when we shouldn't
if (_loaded.get(field) == isLoaded)

View File

@ -22,8 +22,6 @@ import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.spi.ClassTransformer;
import javax.persistence.spi.PersistenceProvider;
@ -73,7 +71,7 @@ public class PersistenceProviderImpl
*/
public OpenJPAEntityManagerFactory createEntityManagerFactory(String name,
String resource, Map m) {
PersistenceProductDerivation pd = new PersistenceProductDerivation();
PersistenceProductDerivation pd = newPersistenceProductDerivation();
try {
Object poolValue = Configurations.removeProperty(EMF_POOL, m);
ConfigurationProvider cp = pd.load(resource, name, m);
@ -101,7 +99,7 @@ public class PersistenceProviderImpl
}
if (poolValue == null || !((Boolean) poolValue).booleanValue())
return Bootstrap.newBrokerFactory(cp, loader);
return newBrokerFactory(cp, loader);
else
return Bootstrap.getBrokerFactory(cp, loader);
}
@ -201,4 +199,19 @@ public class PersistenceProviderImpl
return _trans.transform(cl, name, previousVersion, pd, bytes);
}
}
/**
* Return a persistence product deviration with default setting.
*/
public PersistenceProductDerivation newPersistenceProductDerivation() {
return new PersistenceProductDerivation();
}
/**
* Return a broker factory for the given configuration and class loader.
*/
public BrokerFactory newBrokerFactory(ConfigurationProvider cp,
ClassLoader loader) {
return Bootstrap.newBrokerFactory(cp, loader);
}
}