A whole bunch of revampery on the way to collection caching, including some
basic stats reporting and query and cache logging. PersistenceContext no longer sticks its nose so deeply into the business of Query and Modifier. It just passes itself along and allows them to do any cache activity they need during their normal execution. The one situation where we keep our nose in their business is to allow a Query to return a result from the cache before it is even invoked so that we can avoid requesting a database connection if we won't ever need one.
This commit is contained in:
@@ -578,7 +578,7 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
// check to see if our schema version table exists, create it if not
|
// check to see if our schema version table exists, create it if not
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
liaison.createTableIfMissing(
|
liaison.createTableIfMissing(
|
||||||
conn, SCHEMA_VERSION_TABLE,
|
conn, SCHEMA_VERSION_TABLE,
|
||||||
new String[] { P_COLUMN, V_COLUMN, MV_COLUMN },
|
new String[] { P_COLUMN, V_COLUMN, MV_COLUMN },
|
||||||
@@ -697,7 +697,7 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
final Iterable<Index> indexen = _indexes.values();
|
final Iterable<Index> indexen = _indexes.values();
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
// create the table
|
// create the table
|
||||||
String[] primaryKeyColumns = null;
|
String[] primaryKeyColumns = null;
|
||||||
if (_pkColumns != null) {
|
if (_pkColumns != null) {
|
||||||
@@ -803,8 +803,8 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
if (hasPrimaryKey() && metaData.pkName == null) {
|
if (hasPrimaryKey() && metaData.pkName == null) {
|
||||||
log.info("Adding primary key.");
|
log.info("Adding primary key.");
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
@Override public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
@Override
|
||||||
throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
liaison.addPrimaryKey(
|
liaison.addPrimaryKey(
|
||||||
conn, getTableName(), fieldsToColumns(getPrimaryKeyFields()));
|
conn, getTableName(), fieldsToColumns(getPrimaryKeyFields()));
|
||||||
return 0;
|
return 0;
|
||||||
@@ -815,8 +815,8 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
final String pkName = metaData.pkName;
|
final String pkName = metaData.pkName;
|
||||||
log.info("Dropping primary key: " + pkName);
|
log.info("Dropping primary key: " + pkName);
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
@Override public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
@Override
|
||||||
throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
liaison.dropPrimaryKey(conn, getTableName(), pkName);
|
liaison.dropPrimaryKey(conn, getTableName(), pkName);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -833,8 +833,8 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
}
|
}
|
||||||
// but this is a new, named index, so we create it
|
// but this is a new, named index, so we create it
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
@Override public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
@Override
|
||||||
throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
liaison.addIndexToTable(
|
liaison.addIndexToTable(
|
||||||
conn, getTableName(), fieldsToColumns(index.fields()),
|
conn, getTableName(), fieldsToColumns(index.fields()),
|
||||||
ixName, index.unique());
|
ixName, index.unique());
|
||||||
@@ -869,8 +869,8 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
final String[] colArr = colSet.toArray(new String[colSet.size()]);
|
final String[] colArr = colSet.toArray(new String[colSet.size()]);
|
||||||
final String fName = indexName;
|
final String fName = indexName;
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
@Override public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
@Override
|
||||||
throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
liaison.addIndexToTable(conn, getTableName(), colArr, fName, true);
|
liaison.addIndexToTable(conn, getTableName(), colArr, fName, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -891,8 +891,8 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
|
|
||||||
// but not this one, so let's create it
|
// but not this one, so let's create it
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
@Override public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
@Override
|
||||||
throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
builder.addFullTextSearch(conn, DepotMarshaller.this, recordFts);
|
builder.addFullTextSearch(conn, DepotMarshaller.this, recordFts);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -937,8 +937,8 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
// initialValue which will use the new column name to obtain the sequence name which
|
// initialValue which will use the new column name to obtain the sequence name which
|
||||||
// ain't going to work either; we punt!
|
// ain't going to work either; we punt!
|
||||||
ctx.invoke(new Modifier() {
|
ctx.invoke(new Modifier() {
|
||||||
@Override public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
@Override
|
||||||
throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
valgen.create(conn, liaison);
|
valgen.create(conn, liaison);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -983,7 +983,7 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
|
|
||||||
protected abstract class SimpleModifier extends Modifier {
|
protected abstract class SimpleModifier extends Modifier {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
try {
|
try {
|
||||||
return invoke(liaison, stmt);
|
return invoke(liaison, stmt);
|
||||||
@@ -1035,10 +1035,13 @@ public class DepotMarshaller<T extends PersistentRecord>
|
|||||||
throws DatabaseException
|
throws DatabaseException
|
||||||
{
|
{
|
||||||
return ctx.invoke(new Query.Trivial<TableMetaData>() {
|
return ctx.invoke(new Query.Trivial<TableMetaData>() {
|
||||||
@Override public TableMetaData invoke (Connection conn, DatabaseLiaison dl)
|
@Override public TableMetaData invoke (PersistenceContext ctx, Connection conn,
|
||||||
throws SQLException {
|
DatabaseLiaison dl) throws SQLException {
|
||||||
return new TableMetaData(conn.getMetaData(), tableName);
|
return new TableMetaData(conn.getMetaData(), tableName);
|
||||||
}
|
}
|
||||||
|
public void updateStats (Stats stats) {
|
||||||
|
// nothing doing
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import com.google.common.collect.Lists;
|
|||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import com.samskivert.util.ArrayUtil;
|
import com.samskivert.util.ArrayUtil;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
import com.samskivert.jdbc.ConnectionProvider;
|
import com.samskivert.jdbc.ConnectionProvider;
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
@@ -308,7 +309,7 @@ public abstract class DepotRepository
|
|||||||
* the latest data.
|
* the latest data.
|
||||||
*/
|
*/
|
||||||
protected <T extends PersistentRecord> List<Key<T>> findAllKeys (
|
protected <T extends PersistentRecord> List<Key<T>> findAllKeys (
|
||||||
Class<T> type, boolean forUpdate, Collection<? extends QueryClause> clauses)
|
final Class<T> type, boolean forUpdate, Collection<? extends QueryClause> clauses)
|
||||||
throws DatabaseException
|
throws DatabaseException
|
||||||
{
|
{
|
||||||
final List<Key<T>> keys = Lists.newArrayList();
|
final List<Key<T>> keys = Lists.newArrayList();
|
||||||
@@ -319,36 +320,53 @@ public abstract class DepotRepository
|
|||||||
|
|
||||||
if (forUpdate) {
|
if (forUpdate) {
|
||||||
_ctx.invoke(new Modifier(null) {
|
_ctx.invoke(new Modifier(null) {
|
||||||
@Override public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
@Override
|
||||||
throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
PreparedStatement stmt = builder.prepare(conn);
|
||||||
try {
|
try {
|
||||||
ResultSet rs = stmt.executeQuery();
|
ResultSet rs = stmt.executeQuery();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
keys.add(marsh.makePrimaryKey(rs));
|
keys.add(marsh.makePrimaryKey(rs));
|
||||||
}
|
}
|
||||||
|
// TODO: cache this result?
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Loaded " + StringUtil.shortClassName(type) + " keys",
|
||||||
|
"count", keys.size());
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} finally {
|
} finally {
|
||||||
JDBCUtil.close(stmt);
|
JDBCUtil.close(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override public void updateStats (Stats stats) {
|
||||||
|
stats.noteQuery(0, 1, 0, 0); // one uncached query
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_ctx.invoke(new Query.Trivial<Void>() {
|
_ctx.invoke(new Query.Trivial<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
public Void invoke (PersistenceContext ctx, Connection conn,
|
||||||
|
DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
PreparedStatement stmt = builder.prepare(conn);
|
||||||
try {
|
try {
|
||||||
ResultSet rs = stmt.executeQuery();
|
ResultSet rs = stmt.executeQuery();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
keys.add(marsh.makePrimaryKey(rs));
|
keys.add(marsh.makePrimaryKey(rs));
|
||||||
}
|
}
|
||||||
|
// TODO: cache this result?
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Loaded " + StringUtil.shortClassName(type) + " keys",
|
||||||
|
"count", keys.size());
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
JDBCUtil.close(stmt);
|
JDBCUtil.close(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void updateStats (Stats stats) {
|
||||||
|
stats.noteQuery(0, 1, 0, 0); // one uncached query
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +393,7 @@ public abstract class DepotRepository
|
|||||||
// key will be null if record was supplied without a primary key
|
// key will be null if record was supplied without a primary key
|
||||||
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
|
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
// if needed, update our modifier's key so that it can cache our results
|
// if needed, update our modifier's key so that it can cache our results
|
||||||
Set<String> identityFields = Collections.emptySet();
|
Set<String> identityFields = Collections.emptySet();
|
||||||
if (_key == null) {
|
if (_key == null) {
|
||||||
@@ -427,7 +445,7 @@ public abstract class DepotRepository
|
|||||||
|
|
||||||
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
|
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
PreparedStatement stmt = builder.prepare(conn);
|
||||||
try {
|
try {
|
||||||
return stmt.executeUpdate();
|
return stmt.executeUpdate();
|
||||||
@@ -464,7 +482,7 @@ public abstract class DepotRepository
|
|||||||
|
|
||||||
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
|
return _ctx.invoke(new CachingModifier<T>(record, key, key) {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
PreparedStatement stmt = builder.prepare(conn);
|
||||||
// clear out _result so that we don't rewrite this partial record to the cache
|
// clear out _result so that we don't rewrite this partial record to the cache
|
||||||
_result = null;
|
_result = null;
|
||||||
@@ -604,7 +622,7 @@ public abstract class DepotRepository
|
|||||||
|
|
||||||
return _ctx.invoke(new Modifier(invalidator) {
|
return _ctx.invoke(new Modifier(invalidator) {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
PreparedStatement stmt = builder.prepare(conn);
|
||||||
try {
|
try {
|
||||||
return stmt.executeUpdate();
|
return stmt.executeUpdate();
|
||||||
@@ -735,7 +753,7 @@ public abstract class DepotRepository
|
|||||||
|
|
||||||
return _ctx.invoke(new Modifier(invalidator) {
|
return _ctx.invoke(new Modifier(invalidator) {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
PreparedStatement stmt = builder.prepare(conn);
|
||||||
try {
|
try {
|
||||||
return stmt.executeUpdate();
|
return stmt.executeUpdate();
|
||||||
@@ -773,7 +791,7 @@ public abstract class DepotRepository
|
|||||||
final boolean[] created = new boolean[1];
|
final boolean[] created = new boolean[1];
|
||||||
_ctx.invoke(new CachingModifier<T>(record, key, key) {
|
_ctx.invoke(new CachingModifier<T>(record, key, key) {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = null;
|
PreparedStatement stmt = null;
|
||||||
try {
|
try {
|
||||||
if (_key != null) {
|
if (_key != null) {
|
||||||
@@ -897,7 +915,7 @@ public abstract class DepotRepository
|
|||||||
|
|
||||||
return _ctx.invoke(new Modifier(invalidator) {
|
return _ctx.invoke(new Modifier(invalidator) {
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
PreparedStatement stmt = builder.prepare(conn);
|
PreparedStatement stmt = builder.prepare(conn);
|
||||||
try {
|
try {
|
||||||
return stmt.executeUpdate();
|
return stmt.executeUpdate();
|
||||||
|
|||||||
@@ -75,13 +75,12 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectClause<T> select =
|
_select = new SelectClause<T>(_type, _marsh.getPrimaryKeyFields(), clauses);
|
||||||
new SelectClause<T>(_type, _marsh.getPrimaryKeyFields(), clauses);
|
_builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select));
|
||||||
_builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, select));
|
_builder.newQuery(_select);
|
||||||
_builder.newQuery(select);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> invoke (Connection conn, DatabaseLiaison liaison)
|
public List<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
Map<Key<T>, T> entities = Maps.newHashMap();
|
Map<Key<T>, T> entities = Maps.newHashMap();
|
||||||
@@ -96,15 +95,11 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
Key<T> key = _marsh.makePrimaryKey(rs);
|
Key<T> key = _marsh.makePrimaryKey(rs);
|
||||||
allKeys.add(key);
|
allKeys.add(key);
|
||||||
|
|
||||||
// TODO: All this cache fiddling needs to move to PersistenceContext?
|
T value = _ctx.<T>cacheLookup(key);
|
||||||
CacheAdapter.CachedValue<T> hit = _ctx.cacheLookup(key);
|
if (value != null) {
|
||||||
if (hit != null) {
|
@SuppressWarnings("unchecked") T newValue = (T) value.clone();
|
||||||
T value = hit.getValue();
|
entities.put(key, newValue);
|
||||||
if (value != null) {
|
continue;
|
||||||
@SuppressWarnings("unchecked") T newValue = (T) value.clone();
|
|
||||||
entities.put(key, newValue);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchKeys.add(key);
|
fetchKeys.add(key);
|
||||||
@@ -114,8 +109,23 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
JDBCUtil.close(stmt);
|
JDBCUtil.close(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadAndResolve(conn, allKeys, fetchKeys, entities, stmtString);
|
_cachedRecords = entities.size();
|
||||||
|
_uncachedRecords = fetchKeys.size();
|
||||||
|
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Loaded " + _marsh.getTableName(), "query", _select,
|
||||||
|
"keys", keysToString(allKeys));
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadAndResolve(ctx, conn, allKeys, fetchKeys, entities, stmtString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateStats (Stats stats) {
|
||||||
|
stats.noteQuery(0, 1, _cachedRecords, _uncachedRecords); // one uncached query
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SelectClause<T> _select;
|
||||||
|
protected int _cachedRecords, _uncachedRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,29 +142,33 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
_builder = ctx.getSQLBuilder(new DepotTypes(ctx, _type));
|
_builder = ctx.getSQLBuilder(new DepotTypes(ctx, _type));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> invoke (Connection conn, DatabaseLiaison liaison)
|
public List<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
Map<Key<T>, T> entities = Maps.newHashMap();
|
Map<Key<T>, T> entities = Maps.newHashMap();
|
||||||
Set<Key<T>> fetchKeys = Sets.newHashSet();
|
Set<Key<T>> fetchKeys = Sets.newHashSet();
|
||||||
for (Key<T> key : _keys) {
|
for (Key<T> key : _keys) {
|
||||||
// TODO: All this cache fiddling needs to move to PersistenceContext?
|
T value = _ctx.<T>cacheLookup(key);
|
||||||
CacheAdapter.CachedValue<T> hit = _ctx.cacheLookup(key);
|
if (value != null) {
|
||||||
if (hit != null) {
|
@SuppressWarnings("unchecked") T newValue = (T) value.clone();
|
||||||
T value = hit.getValue();
|
entities.put(key, newValue);
|
||||||
if (value != null) {
|
continue;
|
||||||
@SuppressWarnings("unchecked") T newValue = (T) value.clone();
|
|
||||||
entities.put(key, newValue);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fetchKeys.add(key);
|
fetchKeys.add(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadAndResolve(conn, _keys, fetchKeys, entities, null);
|
_cachedRecords = entities.size();
|
||||||
|
_uncachedRecords = fetchKeys.size();
|
||||||
|
|
||||||
|
return loadAndResolve(ctx, conn, _keys, fetchKeys, entities, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateStats (Stats stats) {
|
||||||
|
stats.noteQuery(0, 0, _cachedRecords, _uncachedRecords);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection<Key<T>> _keys;
|
protected Collection<Key<T>> _keys;
|
||||||
|
protected int _cachedRecords, _uncachedRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,12 +182,12 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
throws DatabaseException
|
throws DatabaseException
|
||||||
{
|
{
|
||||||
super(ctx, type);
|
super(ctx, type);
|
||||||
SelectClause<T> select = new SelectClause<T>(type, _marsh.getFieldNames(), clauses);
|
_select = new SelectClause<T>(type, _marsh.getFieldNames(), clauses);
|
||||||
_builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, select));
|
_builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select));
|
||||||
_builder.newQuery(select);
|
_builder.newQuery(_select);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> invoke (Connection conn, DatabaseLiaison liaison)
|
public List<T> invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
List<T> result = Lists.newArrayList();
|
List<T> result = Lists.newArrayList();
|
||||||
@@ -182,12 +196,25 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
ResultSet rs = stmt.executeQuery();
|
ResultSet rs = stmt.executeQuery();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
result.add(_marsh.createObject(rs));
|
result.add(_marsh.createObject(rs));
|
||||||
|
_uncachedRecords++;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
JDBCUtil.close(stmt);
|
JDBCUtil.close(stmt);
|
||||||
}
|
}
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Loaded " + _marsh.getTableName(), "query", _select,
|
||||||
|
"uncached", _uncachedRecords);
|
||||||
|
}
|
||||||
|
// TODO: do we want to cache these results?
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateStats (Stats stats) {
|
||||||
|
stats.noteQuery(0, 1, 0, _uncachedRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SelectClause<T> _select;
|
||||||
|
protected int _uncachedRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FindAllQuery (PersistenceContext ctx, Class<T> type)
|
public FindAllQuery (PersistenceContext ctx, Class<T> type)
|
||||||
@@ -198,45 +225,46 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
_marsh = _ctx.getMarshaller(type);
|
_marsh = _ctx.getMarshaller(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Query
|
// from interface Query
|
||||||
public CacheKey getCacheKey ()
|
public List<T> getCachedResult (PersistenceContext ctx)
|
||||||
{
|
{
|
||||||
return null;
|
return null; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Query
|
// // from interface Query
|
||||||
public void updateCache (PersistenceContext ctx, List<T> result) {
|
// public List<T> transformCacheHit (CacheKey key, List<T> bits)
|
||||||
if (_marsh.hasPrimaryKey()) {
|
// {
|
||||||
for (T bit : result) {
|
// if (bits == null) {
|
||||||
ctx.cacheStore(_marsh.getPrimaryKey(bit), bit.clone());
|
// return bits;
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// from Query
|
// List<T> result = Lists.newArrayList();
|
||||||
public List<T> transformCacheHit (CacheKey key, List<T> bits)
|
// for (T bit : bits) {
|
||||||
|
// if (bit != null) {
|
||||||
|
// @SuppressWarnings("unchecked") T cbit = (T) bit.clone();
|
||||||
|
// result.add(cbit);
|
||||||
|
// } else {
|
||||||
|
// result.add(null);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// from interface Operation
|
||||||
|
public void updateStats (Stats stats)
|
||||||
{
|
{
|
||||||
if (bits == null) {
|
// TODO
|
||||||
return bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<T> result = Lists.newArrayList();
|
|
||||||
for (T bit : bits) {
|
|
||||||
if (bit != null) {
|
|
||||||
@SuppressWarnings("unchecked") T cbit = (T) bit.clone();
|
|
||||||
result.add(cbit);
|
|
||||||
} else {
|
|
||||||
result.add(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<T> loadAndResolve (Connection conn, Collection<Key<T>> allKeys,
|
protected List<T> loadAndResolve (PersistenceContext ctx, Connection conn,
|
||||||
Set<Key<T>> fetchKeys, Map<Key<T>, T> entities,
|
Collection<Key<T>> allKeys, Set<Key<T>> fetchKeys,
|
||||||
String origStmt)
|
Map<Key<T>, T> entities, String origStmt)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
|
if (PersistenceContext.CACHE_DEBUG && fetchKeys.size() > 0) {
|
||||||
|
log.info("Loading " + _marsh.getTableName(), "keys", keysToString(fetchKeys));
|
||||||
|
}
|
||||||
|
|
||||||
// if we're fetching a huge number of records, we have to do it in multiple queries
|
// if we're fetching a huge number of records, we have to do it in multiple queries
|
||||||
if (fetchKeys.size() > In.MAX_KEYS) {
|
if (fetchKeys.size() > In.MAX_KEYS) {
|
||||||
int keyCount = fetchKeys.size();
|
int keyCount = fetchKeys.size();
|
||||||
@@ -248,11 +276,11 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
iter.remove();
|
iter.remove();
|
||||||
}
|
}
|
||||||
keyCount -= keys.size();
|
keyCount -= keys.size();
|
||||||
loadRecords(conn, keys, entities, origStmt);
|
loadRecords(ctx, conn, keys, entities, origStmt);
|
||||||
} while (keyCount > 0);
|
} while (keyCount > 0);
|
||||||
|
|
||||||
} else if (fetchKeys.size() > 0) {
|
} else if (fetchKeys.size() > 0) {
|
||||||
loadRecords(conn, fetchKeys, entities, origStmt);
|
loadRecords(ctx, conn, fetchKeys, entities, origStmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<T> result = Lists.newArrayList();
|
List<T> result = Lists.newArrayList();
|
||||||
@@ -265,10 +293,11 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadRecords (Connection conn, Set<Key<T>> keys, Map<Key<T>, T> entities,
|
protected void loadRecords (PersistenceContext ctx, Connection conn, Set<Key<T>> keys,
|
||||||
String origStmt)
|
Map<Key<T>, T> entities, String origStmt)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
|
boolean hasPrimaryKey = _marsh.hasPrimaryKey();
|
||||||
_builder.newQuery(new SelectClause<T>(_type, _marsh.getFieldNames(),
|
_builder.newQuery(new SelectClause<T>(_type, _marsh.getFieldNames(),
|
||||||
new KeySet<T>(_type, keys)));
|
new KeySet<T>(_type, keys)));
|
||||||
PreparedStatement stmt = _builder.prepare(conn);
|
PreparedStatement stmt = _builder.prepare(conn);
|
||||||
@@ -282,6 +311,10 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
if (entities.put(key, obj) != null) {
|
if (entities.put(key, obj) != null) {
|
||||||
dups++;
|
dups++;
|
||||||
}
|
}
|
||||||
|
// cache our result if it has a primary key
|
||||||
|
if (hasPrimaryKey) {
|
||||||
|
ctx.cacheStore(_marsh.getPrimaryKey(obj), obj.clone());
|
||||||
|
}
|
||||||
got.add(key);
|
got.add(key);
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
@@ -292,11 +325,27 @@ public abstract class FindAllQuery<T extends PersistentRecord>
|
|||||||
"wanted", keys, "got", got, "dups", dups, new Exception());
|
"wanted", keys, "got", got, "dups", dups, new Exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Cached " + _marsh.getTableName(), "count", cnt);
|
||||||
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
JDBCUtil.close(stmt);
|
JDBCUtil.close(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String keysToString (Iterable<Key<T>> keySet)
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder("(");
|
||||||
|
for (Key<T> key : keySet) {
|
||||||
|
if (builder.length() > 1) {
|
||||||
|
builder.append(", ");
|
||||||
|
}
|
||||||
|
key.toShortString(builder);
|
||||||
|
}
|
||||||
|
return builder.append(")").toString();
|
||||||
|
}
|
||||||
|
|
||||||
protected PersistenceContext _ctx;
|
protected PersistenceContext _ctx;
|
||||||
protected SQLBuilder _builder;
|
protected SQLBuilder _builder;
|
||||||
protected DepotMarshaller<T> _marsh;
|
protected DepotMarshaller<T> _marsh;
|
||||||
|
|||||||
@@ -27,9 +27,13 @@ import java.sql.SQLException;
|
|||||||
|
|
||||||
import com.samskivert.jdbc.DatabaseLiaison;
|
import com.samskivert.jdbc.DatabaseLiaison;
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
import com.samskivert.jdbc.JDBCUtil;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
import com.samskivert.depot.clause.QueryClause;
|
import com.samskivert.depot.clause.QueryClause;
|
||||||
import com.samskivert.depot.clause.SelectClause;
|
import com.samskivert.depot.clause.SelectClause;
|
||||||
|
|
||||||
|
import static com.samskivert.depot.Log.log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The implementation of {@link DepotRepository#load} functionality.
|
* The implementation of {@link DepotRepository#load} functionality.
|
||||||
*/
|
*/
|
||||||
@@ -49,21 +53,30 @@ public class FindOneQuery<T extends PersistentRecord>
|
|||||||
_builder.newQuery(_select);
|
_builder.newQuery(_select);
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Query
|
// from interface Query
|
||||||
public CacheKey getCacheKey ()
|
public T getCachedResult (PersistenceContext ctx)
|
||||||
{
|
{
|
||||||
WhereClause where = _select.getWhereClause();
|
CacheKey key = getCacheKey();
|
||||||
if (where != null && where instanceof CacheKey) {
|
if (key == null) {
|
||||||
return (CacheKey) where;
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
T value = ctx.<T>cacheLookup(key);
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
_cachedRecords = 1;
|
||||||
|
// we do not want to return a reference to the actual cached entity so we clone it
|
||||||
|
@SuppressWarnings("unchecked") T cvalue = (T) value.clone();
|
||||||
|
return cvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Query
|
// from interface Query
|
||||||
public T invoke (Connection conn, DatabaseLiaison liaison) throws SQLException
|
public T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
|
throws SQLException
|
||||||
{
|
{
|
||||||
PreparedStatement stmt = _builder.prepare(conn);
|
PreparedStatement stmt = _builder.prepare(conn);
|
||||||
try {
|
try {
|
||||||
|
// load up the record in question
|
||||||
T result = null;
|
T result = null;
|
||||||
ResultSet rs = stmt.executeQuery();
|
ResultSet rs = stmt.executeQuery();
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
@@ -71,6 +84,25 @@ public class FindOneQuery<T extends PersistentRecord>
|
|||||||
}
|
}
|
||||||
// TODO: if (rs.next()) issue warning?
|
// TODO: if (rs.next()) issue warning?
|
||||||
rs.close();
|
rs.close();
|
||||||
|
|
||||||
|
// potentially cache the result
|
||||||
|
CacheKey key = getCacheKey();
|
||||||
|
if (key == null) {
|
||||||
|
// no row-specific cache key was given, if we can, create a key from the record
|
||||||
|
if (result != null && _marsh.hasPrimaryKey()) {
|
||||||
|
key = _marsh.getPrimaryKey(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Loaded " + (key != null ? key : _marsh.getTableName()));
|
||||||
|
}
|
||||||
|
if (key != null) {
|
||||||
|
ctx.cacheStore(key, (result != null) ? result.clone() : null);
|
||||||
|
if (PersistenceContext.CACHE_DEBUG) {
|
||||||
|
log.info("Cached " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
@@ -78,33 +110,20 @@ public class FindOneQuery<T extends PersistentRecord>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Query
|
// from interface Operation
|
||||||
public void updateCache (PersistenceContext ctx, T result)
|
public void updateStats (Stats stats)
|
||||||
{
|
{
|
||||||
CacheKey key = getCacheKey();
|
stats.noteQuery(0, 0, _cachedRecords, 1-_cachedRecords);
|
||||||
if (key == null) {
|
|
||||||
// no row-specific cache key was given
|
|
||||||
if (result == null || !_marsh.hasPrimaryKey()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// if we can, create a key from what was actually returned
|
|
||||||
key = _marsh.getPrimaryKey(result);
|
|
||||||
}
|
|
||||||
ctx.cacheStore(key, (result != null) ? result.clone() : null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// from Query
|
protected CacheKey getCacheKey ()
|
||||||
public T transformCacheHit (CacheKey key, T value)
|
|
||||||
{
|
{
|
||||||
if (value == null) {
|
WhereClause where = _select.getWhereClause();
|
||||||
return null;
|
return (where != null && where instanceof CacheKey) ? (CacheKey)where : null;
|
||||||
}
|
|
||||||
// we do not want to return a reference to the actual cached entity so we clone it
|
|
||||||
@SuppressWarnings("unchecked") T cvalue = (T) value.clone();
|
|
||||||
return cvalue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DepotMarshaller<T> _marsh;
|
protected DepotMarshaller<T> _marsh;
|
||||||
protected SelectClause<T> _select;
|
protected SelectClause<T> _select;
|
||||||
protected SQLBuilder _builder;
|
protected SQLBuilder _builder;
|
||||||
|
protected int _cachedRecords;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,6 +199,20 @@ public class Key<T extends PersistentRecord> extends WhereClause
|
|||||||
ctx.cacheInvalidate(this);
|
ctx.cacheInvalidate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends just the key=value portion of our {@link #toString} to the supplied buffer.
|
||||||
|
*/
|
||||||
|
public void toShortString (StringBuilder builder)
|
||||||
|
{
|
||||||
|
String[] keyFields = KeyUtil.getKeyFields(_pClass);
|
||||||
|
for (int ii = 0; ii < keyFields.length; ii ++) {
|
||||||
|
if (ii > 0) {
|
||||||
|
builder.append(":");
|
||||||
|
}
|
||||||
|
builder.append(keyFields[ii]).append("=").append(_values.get(ii));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override // from WhereClause
|
@Override // from WhereClause
|
||||||
public void validateQueryType (Class<?> pClass)
|
public void validateQueryType (Class<?> pClass)
|
||||||
{
|
{
|
||||||
@@ -229,13 +243,7 @@ public class Key<T extends PersistentRecord> extends WhereClause
|
|||||||
{
|
{
|
||||||
StringBuilder builder = new StringBuilder(_pClass.getSimpleName());
|
StringBuilder builder = new StringBuilder(_pClass.getSimpleName());
|
||||||
builder.append("(");
|
builder.append("(");
|
||||||
String[] keyFields = KeyUtil.getKeyFields(_pClass);
|
toShortString(builder);
|
||||||
for (int ii = 0; ii < keyFields.length; ii ++) {
|
|
||||||
if (ii > 0) {
|
|
||||||
builder.append(", ");
|
|
||||||
}
|
|
||||||
builder.append(keyFields[ii]).append("=").append(_values.get(ii));
|
|
||||||
}
|
|
||||||
builder.append(")");
|
builder.append(")");
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// Depot library - a Java relational persistence library
|
// Depot library - a Java relational persistence library
|
||||||
// Copyright (C) 2006-2008 Michael Bayne and Pär Winzell
|
// Copyright (C) 2006-2008 Michael Bayne and Pär Winzell
|
||||||
//
|
//
|
||||||
// This library is free software; you can redistribute it and/or modify it
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
// under the terms of the GNU Lesser General Public License as published
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
@@ -41,8 +41,8 @@ public abstract class Modifier implements Operation<Integer>
|
|||||||
super(null);
|
super(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override // from Modifier
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
try {
|
try {
|
||||||
return stmt.executeUpdate(createQuery(liaison));
|
return stmt.executeUpdate(createQuery(liaison));
|
||||||
@@ -86,25 +86,21 @@ public abstract class Modifier implements Operation<Integer>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override // from Modifier
|
@Override // from Modifier
|
||||||
public void cacheUpdate (PersistenceContext ctx)
|
public Integer invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
|
throws SQLException
|
||||||
{
|
{
|
||||||
super.cacheUpdate(ctx);
|
Integer rows = super.invoke(ctx, conn, liaison);
|
||||||
// if we have both a key and a record, cache
|
// if we have both a key and a record, cache
|
||||||
if (_key != null && _result != null) {
|
if (_key != null && _result != null) {
|
||||||
ctx.cacheStore(_key, _result.clone());
|
ctx.cacheStore(_key, _result.clone());
|
||||||
}
|
}
|
||||||
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CacheKey _key;
|
protected CacheKey _key;
|
||||||
protected T _result;
|
protected T _result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Overriden to perform the actual database modifications represented by this object; should
|
|
||||||
* return the number of modified rows.
|
|
||||||
*/
|
|
||||||
public abstract Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@link Modifier} without a cache invalidator.
|
* Constructs a {@link Modifier} without a cache invalidator.
|
||||||
*/
|
*/
|
||||||
@@ -121,24 +117,27 @@ public abstract class Modifier implements Operation<Integer>
|
|||||||
_invalidator = invalidator;
|
_invalidator = invalidator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// from interface Operation
|
||||||
* Do any cache invalidation needed for this modification. This method is called just
|
public Integer invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
* before the database statement is executed.
|
throws SQLException
|
||||||
*/
|
|
||||||
public void cacheInvalidation (PersistenceContext ctx)
|
|
||||||
{
|
{
|
||||||
if (_invalidator != null) {
|
if (_invalidator != null) {
|
||||||
_invalidator.invalidate(ctx);
|
_invalidator.invalidate(ctx);
|
||||||
}
|
}
|
||||||
|
return invoke(conn, liaison);
|
||||||
|
}
|
||||||
|
|
||||||
|
// from interface Operation
|
||||||
|
public void updateStats (Stats stats)
|
||||||
|
{
|
||||||
|
// nothing to update for modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do any cache updates needed for this modification. This method is called just after
|
* Overriden to perform the actual database modifications represented by this object; should
|
||||||
* the successful execution of the database statement.
|
* return the number of modified rows.
|
||||||
*/
|
*/
|
||||||
public void cacheUpdate (PersistenceContext ctx)
|
protected abstract int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CacheInvalidator _invalidator;
|
protected CacheInvalidator _invalidator;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ public interface Operation<T>
|
|||||||
/**
|
/**
|
||||||
* Performs the actual JDBC interactions associated with this operation.
|
* Performs the actual JDBC interactions associated with this operation.
|
||||||
*/
|
*/
|
||||||
public T invoke (Connection conn, DatabaseLiaison liaison)
|
public T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
throws SQLException;
|
throws SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the operation has been invoked so that it can update our runtime statistics.
|
||||||
|
*/
|
||||||
|
public void updateStats (Stats stats);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ public class PersistenceContext
|
|||||||
/** Allow toggling of query logging and other debug output via a system property. */
|
/** Allow toggling of query logging and other debug output via a system property. */
|
||||||
public static final boolean DEBUG = Boolean.getBoolean("com.samskivert.depot.debug");
|
public static final boolean DEBUG = Boolean.getBoolean("com.samskivert.depot.debug");
|
||||||
|
|
||||||
|
/** Allow toggling of cache-related logging via a system property. */
|
||||||
|
public static final boolean CACHE_DEBUG = Boolean.getBoolean("com.samskivert.depot.cache_debug");
|
||||||
|
|
||||||
/** Map {@link TableGenerator} instances by name. */
|
/** Map {@link TableGenerator} instances by name. */
|
||||||
public Map<String, TableGenerator> tableGenerators = Maps.newHashMap();
|
public Map<String, TableGenerator> tableGenerators = Maps.newHashMap();
|
||||||
|
|
||||||
@@ -173,6 +176,14 @@ public class PersistenceContext
|
|||||||
_conprov.shutdown();
|
_conprov.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a snapshot of our current runtime statistics.
|
||||||
|
*/
|
||||||
|
public Stats.Snapshot getStats ()
|
||||||
|
{
|
||||||
|
return _stats.getSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and return a new {@link SQLBuilder} for the appropriate dialect.
|
* Create and return a new {@link SQLBuilder} for the appropriate dialect.
|
||||||
*
|
*
|
||||||
@@ -258,26 +269,14 @@ public class PersistenceContext
|
|||||||
public <T> T invoke (Query<T> query)
|
public <T> T invoke (Query<T> query)
|
||||||
throws DatabaseException
|
throws DatabaseException
|
||||||
{
|
{
|
||||||
CacheKey key = query.getCacheKey();
|
// we check to see if the query is already cached before invoking it to avoid requesting a
|
||||||
// if there is a cache key, check the cache
|
// database connection if we don't actually need one
|
||||||
if (key != null && _cache != null) {
|
T result = query.getCachedResult(this);
|
||||||
CacheAdapter.CachedValue<T> cacheHit = cacheLookup(key);
|
if (result != null) {
|
||||||
if (cacheHit != null) {
|
query.updateStats(_stats);
|
||||||
log.debug("cache hit [key=" + key + ", hit=" + cacheHit + "]");
|
return result;
|
||||||
T value = cacheHit.getValue();
|
|
||||||
value = query.transformCacheHit(key, value);
|
|
||||||
if (value != null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
log.debug("transformCacheHit returned null; rejecting cached value.");
|
|
||||||
}
|
|
||||||
log.debug("cache miss [key=" + key + "]");
|
|
||||||
}
|
}
|
||||||
// otherwise, perform the query
|
return invoke(query, true);
|
||||||
T result = invoke(query, true);
|
|
||||||
// and let the caller figure out if it wants to cache itself somehow
|
|
||||||
query.updateCache(this, result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -286,12 +285,7 @@ public class PersistenceContext
|
|||||||
public int invoke (Modifier modifier)
|
public int invoke (Modifier modifier)
|
||||||
throws DatabaseException
|
throws DatabaseException
|
||||||
{
|
{
|
||||||
modifier.cacheInvalidation(this);
|
return invoke(modifier, true);
|
||||||
int rows = invoke(modifier, true);
|
|
||||||
if (rows > 0) {
|
|
||||||
modifier.cacheUpdate(this);
|
|
||||||
}
|
|
||||||
return rows;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -305,13 +299,14 @@ public class PersistenceContext
|
|||||||
/**
|
/**
|
||||||
* Looks up an entry in the cache by the given key.
|
* Looks up an entry in the cache by the given key.
|
||||||
*/
|
*/
|
||||||
public <T> CacheAdapter.CachedValue<T> cacheLookup (CacheKey key)
|
public <T> T cacheLookup (CacheKey key)
|
||||||
{
|
{
|
||||||
if (_cache == null) {
|
if (_cache == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
CacheAdapter.CacheBin<T> bin = _cache.getCache(key.getCacheId());
|
CacheAdapter.CacheBin<T> bin = _cache.getCache(key.getCacheId());
|
||||||
return bin.lookup(key.getCacheKey());
|
CacheAdapter.CachedValue<T> ref = bin.lookup(key.getCacheKey());
|
||||||
|
return (ref == null) ? null : ref.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -530,6 +525,7 @@ public class PersistenceContext
|
|||||||
|
|
||||||
boolean isReadOnly = !(op instanceof Modifier);
|
boolean isReadOnly = !(op instanceof Modifier);
|
||||||
Connection conn;
|
Connection conn;
|
||||||
|
long preConnect = System.nanoTime();
|
||||||
try {
|
try {
|
||||||
conn = _conprov.getConnection(_ident, isReadOnly);
|
conn = _conprov.getConnection(_ident, isReadOnly);
|
||||||
} catch (PersistenceException pe) {
|
} catch (PersistenceException pe) {
|
||||||
@@ -541,10 +537,15 @@ public class PersistenceContext
|
|||||||
// connection pooling which will block in getConnection() instead of returning a connection
|
// connection pooling which will block in getConnection() instead of returning a connection
|
||||||
// that someone else may be using
|
// that someone else may be using
|
||||||
synchronized (conn) {
|
synchronized (conn) {
|
||||||
|
long preInvoke = System.nanoTime();
|
||||||
try {
|
try {
|
||||||
// if this becomes more complex than this single statement, then this should turn
|
// invoke our database operation
|
||||||
// into a method call that contains the complexity
|
T value = op.invoke(this, conn, _liaison);
|
||||||
return op.invoke(conn, _liaison);
|
// note the time it took to invoke this operation
|
||||||
|
_stats.noteOp(isReadOnly, preConnect, preInvoke, System.nanoTime());
|
||||||
|
// have the operation update any appropriate runtime statistics as well
|
||||||
|
op.updateStats(_stats);
|
||||||
|
return value;
|
||||||
|
|
||||||
} catch (SQLException sqe) {
|
} catch (SQLException sqe) {
|
||||||
if (!isReadOnly) {
|
if (!isReadOnly) {
|
||||||
@@ -594,6 +595,9 @@ public class PersistenceContext
|
|||||||
protected DatabaseLiaison _liaison;
|
protected DatabaseLiaison _liaison;
|
||||||
protected boolean _warnOnLazyInit;
|
protected boolean _warnOnLazyInit;
|
||||||
|
|
||||||
|
/** Used to track various statistics. */
|
||||||
|
protected Stats _stats = new Stats();
|
||||||
|
|
||||||
/** The object through which all our caching is relayed, or null, for no caching. */
|
/** The object through which all our caching is relayed, or null, for no caching. */
|
||||||
protected CacheAdapter _cache;
|
protected CacheAdapter _cache;
|
||||||
|
|
||||||
|
|||||||
@@ -34,40 +34,22 @@ public interface Query<T> extends Operation<T>
|
|||||||
/** A simple base class for non-complex queries. */
|
/** A simple base class for non-complex queries. */
|
||||||
public abstract class Trivial<T> implements Query<T>
|
public abstract class Trivial<T> implements Query<T>
|
||||||
{
|
{
|
||||||
public abstract T invoke (Connection conn, DatabaseLiaison liaison) throws SQLException;
|
public abstract T invoke (PersistenceContext ctx, Connection conn, DatabaseLiaison liaison)
|
||||||
|
throws SQLException;
|
||||||
|
|
||||||
public CacheKey getCacheKey () {
|
public T getCachedResult (PersistenceContext ctx) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T transformCacheHit (CacheKey key, T value) {
|
public T transformCacheHit (CacheKey key, T value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateCache (PersistenceContext ctx, T result) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any query may elect to utilize the built-in cache by returning a non-null {@link CacheKey}
|
* If this query has a simple cached result, it should return the non-null result from this
|
||||||
* in this method. This is done automatically by the {@link DepotRepository} when looking up
|
* method. If null is returned, the query will be {@link #invoke}d to obtain its result from
|
||||||
* single entities by primary key, but even entire collections can be cached under a single
|
* persistent storage.
|
||||||
* key.
|
|
||||||
*
|
|
||||||
* Great care must be taken to invalidate such cached collections when their constituent
|
|
||||||
* entities are invalidated. This is generally done using {@link CacheListener} and
|
|
||||||
* {@link CacheInvalidator}.
|
|
||||||
*/
|
*/
|
||||||
public CacheKey getCacheKey ();
|
public T getCachedResult (PersistenceContext ctx);
|
||||||
|
|
||||||
/**
|
|
||||||
* Overriden by subclasses to perform special operations when the query would return a cache
|
|
||||||
* hit. The value may be mutated, modified, or null may be return to force a database hit.
|
|
||||||
*/
|
|
||||||
public T transformCacheHit (CacheKey key, T value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overriden by subclasses to perform case-by-case cache updates.
|
|
||||||
*/
|
|
||||||
public void updateCache (PersistenceContext ctx, T result);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public abstract class SchemaMigration extends Modifier
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
if (!liaison.tableContainsColumn(conn, _tableName, _columnName)) {
|
if (!liaison.tableContainsColumn(conn, _tableName, _columnName)) {
|
||||||
// we'll accept this inconsistency
|
// we'll accept this inconsistency
|
||||||
log.warning(_tableName + "." + _columnName + " already dropped.");
|
log.warning(_tableName + "." + _columnName + " already dropped.");
|
||||||
@@ -78,8 +78,12 @@ public abstract class SchemaMigration extends Modifier
|
|||||||
_newColumnName = newColumnName;
|
_newColumnName = newColumnName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean runBeforeDefault () {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
if (!liaison.tableContainsColumn(conn, _tableName, _oldColumnName)) {
|
if (!liaison.tableContainsColumn(conn, _tableName, _oldColumnName)) {
|
||||||
if (liaison.tableContainsColumn(conn, _tableName, _newColumnName)) {
|
if (liaison.tableContainsColumn(conn, _tableName, _newColumnName)) {
|
||||||
// we'll accept this inconsistency
|
// we'll accept this inconsistency
|
||||||
@@ -104,10 +108,6 @@ public abstract class SchemaMigration extends Modifier
|
|||||||
conn, _tableName, _oldColumnName, _newColumnName, _newColumnDef) ? 1 : 0;
|
conn, _tableName, _oldColumnName, _newColumnName, _newColumnDef) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean runBeforeDefault () {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init (String tableName, Map<String, FieldMarshaller<?>> marshallers) {
|
protected void init (String tableName, Map<String, FieldMarshaller<?>> marshallers) {
|
||||||
super.init(tableName, marshallers);
|
super.init(tableName, marshallers);
|
||||||
@@ -135,18 +135,18 @@ public abstract class SchemaMigration extends Modifier
|
|||||||
_fieldName = fieldName;
|
_fieldName = fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean runBeforeDefault () {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
log.info("Updating type of '" + _fieldName + "' in " + _tableName);
|
log.info("Updating type of '" + _fieldName + "' in " + _tableName);
|
||||||
return liaison.changeColumn(conn, _tableName, _fieldName, _newColumnDef.getType(),
|
return liaison.changeColumn(conn, _tableName, _fieldName, _newColumnDef.getType(),
|
||||||
_newColumnDef.isNullable(), _newColumnDef.isUnique(),
|
_newColumnDef.isNullable(), _newColumnDef.isUnique(),
|
||||||
_newColumnDef.getDefaultValue()) ? 1 : 0;
|
_newColumnDef.getDefaultValue()) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean runBeforeDefault () {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init (String tableName, Map<String, FieldMarshaller<?>> marshallers) {
|
protected void init (String tableName, Map<String, FieldMarshaller<?>> marshallers) {
|
||||||
super.init(tableName, marshallers);
|
super.init(tableName, marshallers);
|
||||||
@@ -174,8 +174,12 @@ public abstract class SchemaMigration extends Modifier
|
|||||||
_defaultValue = defaultValue;
|
_defaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public boolean runBeforeDefault () {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
protected int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||||
// override the default value in the column definition with the one provided
|
// override the default value in the column definition with the one provided
|
||||||
ColumnDefinition defColumnDef = new ColumnDefinition(
|
ColumnDefinition defColumnDef = new ColumnDefinition(
|
||||||
_newColumnDef.getType(), _newColumnDef.isNullable(),
|
_newColumnDef.getType(), _newColumnDef.isNullable(),
|
||||||
@@ -190,10 +194,6 @@ public abstract class SchemaMigration extends Modifier
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean runBeforeDefault () {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init (String tableName, Map<String, FieldMarshaller<?>> marshallers) {
|
protected void init (String tableName, Map<String, FieldMarshaller<?>> marshallers) {
|
||||||
super.init(tableName, marshallers);
|
super.init(tableName, marshallers);
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// Depot library - a Java relational persistence library
|
||||||
|
// Copyright (C) 2006-2008 Michael Bayne and Pär Winzell
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.samskivert.depot;
|
||||||
|
|
||||||
|
import com.samskivert.util.Histogram;
|
||||||
|
|
||||||
|
import static com.samskivert.depot.Log.log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages Depot performance statistics.
|
||||||
|
*/
|
||||||
|
public class Stats
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* An immutable class used to report statistics on repository activity. Statistics are tracked
|
||||||
|
* from the start of the VM and are never reset.
|
||||||
|
*/
|
||||||
|
public static class Snapshot
|
||||||
|
{
|
||||||
|
/** The total number of queries and modifiers executed. */
|
||||||
|
public final int totalOps;
|
||||||
|
|
||||||
|
/** The total number of milliseconds spent waiting for a JDBC connection. */
|
||||||
|
public final long connectionWaitTime;
|
||||||
|
|
||||||
|
/** The total number of collection queries that were loaded from the cache. */
|
||||||
|
public final int cachedQueries;
|
||||||
|
|
||||||
|
/** The total number of collection queries that were loaded from the database. */
|
||||||
|
public final int uncachedQueries;
|
||||||
|
|
||||||
|
/** The number of record loads (individual or as part of a collection query) that were
|
||||||
|
* loaded from the cache. */
|
||||||
|
public final long cachedRecords;
|
||||||
|
|
||||||
|
/** The number of record loads (individual or as part of a collection query) that were
|
||||||
|
* loaded from the database. */
|
||||||
|
public final long uncachedRecords;
|
||||||
|
|
||||||
|
/** A histogram of query durations (with 500ms buckets). */
|
||||||
|
public final Histogram queryHisto;
|
||||||
|
|
||||||
|
/** The total number of milliseconds spent executing queries. */
|
||||||
|
public final long queryTime;
|
||||||
|
|
||||||
|
/** A histogram of modifier durations (with 500ms buckets). */
|
||||||
|
public final Histogram modifierHisto;
|
||||||
|
|
||||||
|
/** The total number of milliseconds spent executing modifiers. */
|
||||||
|
public final long modifierTime;
|
||||||
|
|
||||||
|
/** Creates a stats instance. */
|
||||||
|
protected Snapshot (int totalOps, long connectionWaitTime,
|
||||||
|
int cachedQueries, int uncachedQueries,
|
||||||
|
int cachedRecords, int uncachedRecords,
|
||||||
|
Histogram queryHisto, long queryTime,
|
||||||
|
Histogram modifierHisto, long modifierTime)
|
||||||
|
{
|
||||||
|
this.totalOps = totalOps;
|
||||||
|
this.connectionWaitTime = connectionWaitTime;
|
||||||
|
this.cachedQueries = cachedQueries;
|
||||||
|
this.uncachedQueries = uncachedQueries;
|
||||||
|
this.cachedRecords = cachedRecords;
|
||||||
|
this.uncachedRecords = uncachedRecords;
|
||||||
|
this.queryHisto = queryHisto;
|
||||||
|
this.queryTime = queryTime;
|
||||||
|
this.modifierHisto = modifierHisto;
|
||||||
|
this.modifierTime = modifierTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Snapshot getSnapshot ()
|
||||||
|
{
|
||||||
|
return new Snapshot(_totalOps, _connectionWaitTime,
|
||||||
|
_cachedQueries, _uncachedQueries, _cachedRecords, _uncachedRecords,
|
||||||
|
_readHisto.clone(), _readTime, _writeHisto.clone(), _writeTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void noteOp (
|
||||||
|
boolean isReadOnly, long preConnect, long preInvoke, long postInvoke)
|
||||||
|
{
|
||||||
|
_totalOps++;
|
||||||
|
_connectionWaitTime += (preInvoke - preConnect) / 1000L;
|
||||||
|
|
||||||
|
long opTime = (postInvoke - preInvoke) / 1000L;
|
||||||
|
if (opTime > Integer.MAX_VALUE) {
|
||||||
|
log.warning("ZOMG! A database operation took " + opTime + "ms to complete!");
|
||||||
|
opTime = Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isReadOnly) {
|
||||||
|
_readTime += opTime;
|
||||||
|
_readHisto.addValue((int)opTime);
|
||||||
|
} else {
|
||||||
|
_writeTime += opTime;
|
||||||
|
_writeHisto.addValue((int)opTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void noteQuery (int cachedQueries, int uncachedQueries,
|
||||||
|
int cachedRecords, int uncachedRecords)
|
||||||
|
{
|
||||||
|
_cachedQueries += cachedQueries;
|
||||||
|
_uncachedQueries += uncachedQueries;
|
||||||
|
_cachedRecords += cachedRecords;
|
||||||
|
_uncachedRecords += uncachedRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int _totalOps;
|
||||||
|
protected long _connectionWaitTime;
|
||||||
|
|
||||||
|
protected Histogram _readHisto = new Histogram(0, 500, 20);
|
||||||
|
protected long _readTime;
|
||||||
|
|
||||||
|
protected Histogram _writeHisto = new Histogram(0, 500, 20);
|
||||||
|
protected long _writeTime;
|
||||||
|
|
||||||
|
protected int _cachedQueries, _uncachedQueries;
|
||||||
|
protected int _cachedRecords, _uncachedRecords;
|
||||||
|
}
|
||||||
@@ -195,6 +195,32 @@ public class SelectClause<T extends PersistentRecord> extends QueryClause
|
|||||||
builder.visit(this);
|
builder.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("(where=").append(_where);
|
||||||
|
if (_fromOverride != null) {
|
||||||
|
builder.append(", from=").append(_fromOverride);
|
||||||
|
}
|
||||||
|
if (!_joinClauses.isEmpty()) {
|
||||||
|
builder.append(", join=").append(_joinClauses);
|
||||||
|
}
|
||||||
|
if (_orderBy != null) {
|
||||||
|
builder.append(", orderBy=").append(_orderBy);
|
||||||
|
}
|
||||||
|
if (_groupBy != null) {
|
||||||
|
builder.append(", groupBy=").append(_groupBy);
|
||||||
|
}
|
||||||
|
if (_limit != null) {
|
||||||
|
builder.append(", limit=").append(_limit);
|
||||||
|
}
|
||||||
|
if (_forUpdate != null) {
|
||||||
|
builder.append(", forUpdate=").append(_forUpdate);
|
||||||
|
}
|
||||||
|
return builder.append(")").toString();
|
||||||
|
}
|
||||||
|
|
||||||
/** Persistent class fields mapped to field override clauses. */
|
/** Persistent class fields mapped to field override clauses. */
|
||||||
protected Map<String, FieldDefinition> _disMap = Maps.newHashMap();
|
protected Map<String, FieldDefinition> _disMap = Maps.newHashMap();
|
||||||
|
|
||||||
|
|||||||
@@ -85,6 +85,12 @@ public class Where extends WhereClause
|
|||||||
_condition.addClasses(classSet);
|
_condition.addClasses(classSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return String.valueOf(_condition);
|
||||||
|
}
|
||||||
|
|
||||||
protected static SQLExpression toCondition (ColumnExp[] columns, Comparable<?>[] values)
|
protected static SQLExpression toCondition (ColumnExp[] columns, Comparable<?>[] values)
|
||||||
{
|
{
|
||||||
SQLExpression[] comparisons = new SQLExpression[columns.length];
|
SQLExpression[] comparisons = new SQLExpression[columns.length];
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ public class ColumnExp
|
|||||||
return _pField;
|
return _pField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return "\"" + _pField + "\""; // TODO: qualify with record name and be uber verbose?
|
||||||
|
}
|
||||||
|
|
||||||
/** The table that hosts the column we reference, or null. */
|
/** The table that hosts the column we reference, or null. */
|
||||||
protected final Class<? extends PersistentRecord> _pClass;
|
protected final Class<? extends PersistentRecord> _pClass;
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ public class ValueExp
|
|||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return (_value instanceof Number) ? String.valueOf(_value) : ("'" + _value + "'");
|
||||||
|
}
|
||||||
|
|
||||||
/** The value to be bound to the SQL parameters. */
|
/** The value to be bound to the SQL parameters. */
|
||||||
protected Object _value;
|
protected Object _value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,12 @@ public abstract class Conditionals
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return "IsNull(" + _column + ")";
|
||||||
|
}
|
||||||
|
|
||||||
protected ColumnExp _column;
|
protected ColumnExp _column;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +246,20 @@ public abstract class Conditionals
|
|||||||
_column.addClasses(classSet);
|
_column.addClasses(classSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(_column).append(" in (");
|
||||||
|
for (int ii = 0; ii < _values.length; ii++) {
|
||||||
|
if (ii > 0) {
|
||||||
|
builder.append(", ");
|
||||||
|
}
|
||||||
|
builder.append(_values[ii]);
|
||||||
|
}
|
||||||
|
return builder.append(")").toString();
|
||||||
|
}
|
||||||
|
|
||||||
protected ColumnExp _column;
|
protected ColumnExp _column;
|
||||||
protected Comparable<?>[] _values;
|
protected Comparable<?>[] _values;
|
||||||
}
|
}
|
||||||
@@ -286,6 +306,12 @@ public abstract class Conditionals
|
|||||||
return _clause;
|
return _clause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return "Exists(" + _clause + ")";
|
||||||
|
}
|
||||||
|
|
||||||
protected SelectClause<T> _clause;
|
protected SelectClause<T> _clause;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,6 +355,12 @@ public abstract class Conditionals
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return "FullText(" + _name + "=" + _query + ")";
|
||||||
|
}
|
||||||
|
|
||||||
protected Class<? extends PersistentRecord> _pClass;
|
protected Class<? extends PersistentRecord> _pClass;
|
||||||
protected String _name;
|
protected String _name;
|
||||||
protected String _query;
|
protected String _query;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public abstract class Logic
|
|||||||
|
|
||||||
@Override public String operator()
|
@Override public String operator()
|
||||||
{
|
{
|
||||||
return "or";
|
return " or ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ public abstract class Logic
|
|||||||
|
|
||||||
@Override public String operator()
|
@Override public String operator()
|
||||||
{
|
{
|
||||||
return "and";
|
return " and ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +102,12 @@ public abstract class Logic
|
|||||||
_condition.addClasses(classSet);
|
_condition.addClasses(classSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return "Not(" + _condition + ")";
|
||||||
|
}
|
||||||
|
|
||||||
protected SQLExpression _condition;
|
protected SQLExpression _condition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,19 @@ public interface SQLOperator extends SQLExpression
|
|||||||
*/
|
*/
|
||||||
public abstract String operator ();
|
public abstract String operator ();
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder("(");
|
||||||
|
for (SQLExpression condition : _conditions) {
|
||||||
|
if (builder.length() > 1) {
|
||||||
|
builder.append(operator());
|
||||||
|
}
|
||||||
|
builder.append(condition);
|
||||||
|
}
|
||||||
|
return builder.append(")").toString();
|
||||||
|
}
|
||||||
|
|
||||||
protected SQLExpression[] _conditions;
|
protected SQLExpression[] _conditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +129,12 @@ public interface SQLOperator extends SQLExpression
|
|||||||
return _rhs;
|
return _rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // from Object
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return "(" + _lhs + operator() + _rhs + ")";
|
||||||
|
}
|
||||||
|
|
||||||
protected SQLExpression _lhs;
|
protected SQLExpression _lhs;
|
||||||
protected SQLExpression _rhs;
|
protected SQLExpression _rhs;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user