Formalized the two-phase "get primary keys that match an arbitrary query, then

load or modify the rows that match those keys" pattern so that we can almost
always just magically do the right thing with regard to the cache. Added a
version of deleteAll() that makes use of this.

Also nixed a bunch of checked exception tomfoolery which was almost entirely
unnecessary and now with DatabaseException is completely unnecessary.

A few things remain to be done:

- PrimaryKeySet tries to be "smart" if its passed 0 keys and use
LiteralExp("false") but that causes things to freak out because Depot then
doesn't know what primary class it's dealing with. I'm probably going to make
All and None expressions that match all and none of the records in a table
respectively.

- deleteAll() doesn't currently split its keys into chunks small enough to be
digestible by the database if we match more than 32,768 rows. I'll see if I
can't abstract out that code from FindAllQuery so that we can easily use it
everywhere. It would be cool to handle that a a lower level and allow the
WhereClause to say that it needs to be run in phases, but that would probably
complicate the crap out of the low-level code.

- I need to create PrimaryKey to go between Key and PrimaryKeySet so that we
can avoid duplicating the primary key columns thousands of times in a large
PrimaryKeySet.
This commit is contained in:
Michael Bayne
2008-09-05 19:39:08 +00:00
parent 67bdfda3fe
commit 84622e56c7
36 changed files with 472 additions and 307 deletions
@@ -46,13 +46,15 @@ import com.samskivert.jdbc.depot.expression.LiteralExp;
import com.samskivert.jdbc.depot.expression.SQLExpression;
import com.samskivert.jdbc.depot.expression.ValueExp;
import com.samskivert.jdbc.depot.operator.Conditionals.Exists;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.jdbc.depot.operator.Conditionals.In;
import com.samskivert.jdbc.depot.operator.Conditionals.IsNull;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.jdbc.depot.operator.Logic.Not;
import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator;
import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator;
import com.samskivert.util.StringUtil;
/**
* Implements the base functionality of the argument-binding pass of {@link SQLBuilder}. Dialectal
* subclasses of this should be created and returned from {@link SQLBuilder#getBindVisitor()}.
@@ -62,17 +64,16 @@ import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator;
public class BindVisitor implements ExpressionVisitor
{
public void visit (FromOverride override)
throws Exception
{
// nothing needed
}
public void visit (FieldDefinition fieldOverride)
throws Exception
{
// nothing needed
}
public void visit (WhereCondition<? extends PersistentRecord> whereCondition)
throws Exception
{
for (Comparable<?> value : whereCondition.getValues()) {
if (value != null) {
@@ -81,14 +82,7 @@ public class BindVisitor implements ExpressionVisitor
}
}
public void visit (Key<? extends PersistentRecord> key)
throws Exception
{
key.condition.accept(this);
}
public void visit (MultiKey<? extends PersistentRecord> key)
throws Exception
{
for (Map.Entry<String, Comparable<?>> entry : key.getSingleFieldsMap().entrySet()) {
if (entry.getValue() != null) {
@@ -102,34 +96,31 @@ public class BindVisitor implements ExpressionVisitor
}
public void visit (FunctionExp functionExp)
throws Exception
{
visit(functionExp.getArguments());
}
public void visit (EpochSeconds epochSeconds)
throws Exception
{
epochSeconds.getArgument().accept(this);
}
public void visit (MultiOperator multiOperator)
throws Exception
{
visit(multiOperator.getConditions());
}
public void visit (BinaryOperator binaryOperator) throws Exception
public void visit (BinaryOperator binaryOperator)
{
binaryOperator.getLeftHandSide().accept(this);
binaryOperator.getRightHandSide().accept(this);
}
public void visit (IsNull isNull) throws Exception
public void visit (IsNull isNull)
{
}
public void visit (In in) throws Exception
public void visit (In in)
{
Comparable<?>[] values = in.getValues();
for (int ii = 0; ii < values.length; ii++) {
@@ -137,70 +128,74 @@ public class BindVisitor implements ExpressionVisitor
}
}
public void visit (FullTextMatch match) throws Exception
public void visit (FullTextMatch match)
{
// we never get here
}
public void visit (ColumnExp columnExp) throws Exception
public void visit (ColumnExp columnExp)
{
// no arguments
}
public void visit (Not not) throws Exception
public void visit (Not not)
{
not.getCondition().accept(this);
}
public void visit (GroupBy groupBy) throws Exception
public void visit (GroupBy groupBy)
{
visit(groupBy.getValues());
}
public void visit (ForUpdate forUpdate) throws Exception
public void visit (ForUpdate forUpdate)
{
// do nothing
}
public void visit (OrderBy orderBy) throws Exception
public void visit (OrderBy orderBy)
{
visit(orderBy.getValues());
}
public void visit (Where where) throws Exception
public void visit (WhereClause where)
{
where.getCondition().accept(this);
where.getWhereExpression().accept(this);
}
public void visit (Join join) throws Exception
public void visit (Join join)
{
join.getJoinCondition().accept(this);
}
public void visit (Limit limit) throws Exception
public void visit (Limit limit)
{
_stmt.setInt(_argIdx++, limit.getCount());
_stmt.setInt(_argIdx++, limit.getOffset());
try {
_stmt.setInt(_argIdx++, limit.getCount());
_stmt.setInt(_argIdx++, limit.getOffset());
} catch (SQLException sqe) {
throw new DatabaseException("Failed to configure statement with limit clause " +
"[count=" + limit.getCount() +
", offset=" + limit.getOffset() + "]", sqe);
}
}
public void visit (LiteralExp literalExp) throws Exception
public void visit (LiteralExp literalExp)
{
// do nothing
}
public void visit (ValueExp valueExp) throws Exception
public void visit (ValueExp valueExp)
{
writeValueToStatement(valueExp.getValue());
}
public void visit (Exists<? extends PersistentRecord> exists)
throws Exception
{
exists.getSubClause().accept(this);
}
public void visit (SelectClause<? extends PersistentRecord> selectClause)
throws Exception
{
for (Join clause : selectClause.getJoinClauses()) {
clause.accept(this);
@@ -222,16 +217,21 @@ public class BindVisitor implements ExpressionVisitor
}
}
public void visit (UpdateClause<? extends PersistentRecord> updateClause) throws Exception
public void visit (UpdateClause<? extends PersistentRecord> updateClause)
{
DepotMarshaller<?> marsh = _types.getMarshaller(updateClause.getPersistentClass());
// bind the update arguments
String[] fields = updateClause.getFields();
Object pojo = updateClause.getPojo();
if (pojo != null) {
for (int ii = 0; ii < fields.length; ii ++) {
marsh.getFieldMarshaller(fields[ii]).readFromObject(pojo, _stmt, _argIdx++);
for (String field : updateClause.getFields()) {
try {
marsh.getFieldMarshaller(field).getAndWriteToStatement(_stmt, _argIdx++, pojo);
} catch (Exception e) {
throw new DatabaseException(
"Failed to read field from persistent record and write it to prepared " +
"statement [field=" + field + "]", e);
}
}
} else {
visit(updateClause.getValues());
@@ -239,24 +239,29 @@ public class BindVisitor implements ExpressionVisitor
updateClause.getWhereClause().accept(this);
}
public void visit (DeleteClause<? extends PersistentRecord> deleteClause) throws Exception
{
deleteClause.getWhereClause().accept(this);
}
public void visit (InsertClause<? extends PersistentRecord> insertClause) throws Exception
public void visit (InsertClause<? extends PersistentRecord> insertClause)
{
DepotMarshaller<?> marsh = _types.getMarshaller(insertClause.getPersistentClass());
Object pojo = insertClause.getPojo();
Set<String> idFields = insertClause.getIdentityFields();
for (String field : marsh.getColumnFieldNames()) {
if (!idFields.contains(field)) {
marsh.getFieldMarshaller(field).readFromObject(pojo, _stmt, _argIdx ++);
try {
marsh.getFieldMarshaller(field).getAndWriteToStatement(_stmt, _argIdx++, pojo);
} catch (Exception e) {
throw new DatabaseException(
"Failed to read field from persistent record and write it to prepared " +
"statement [field=" + field + "]", e);
}
}
}
}
public void visit (DeleteClause<? extends PersistentRecord> deleteClause)
{
deleteClause.getWhereClause().accept(this);
}
protected BindVisitor (DepotTypes types, PreparedStatement stmt)
{
_types = types;
@@ -265,7 +270,6 @@ public class BindVisitor implements ExpressionVisitor
}
protected void visit (SQLExpression[] expressions)
throws Exception
{
for (int ii = 0; ii < expressions.length; ii ++) {
expressions[ii].accept(this);
@@ -274,13 +278,17 @@ public class BindVisitor implements ExpressionVisitor
// write the value to the next argument slot in the prepared statement
protected void writeValueToStatement (Object value)
throws SQLException
{
// setObject handles almost all conversions internally, but enums require special care
if (value instanceof ByteEnum) {
_stmt.setByte(_argIdx++, ((ByteEnum)value).toByte());
} else {
_stmt.setObject(_argIdx++, value);
try {
// setObject handles almost all conversions internally, but enums require special care
if (value instanceof ByteEnum) {
_stmt.setByte(_argIdx++, ((ByteEnum)value).toByte());
} else {
_stmt.setObject(_argIdx++, value);
}
} catch (SQLException sqe) {
throw new DatabaseException("Failed to write value to statement [idx=" + (_argIdx-1) +
", value=" + StringUtil.safeToString(value) + "]", sqe);
}
}
@@ -26,7 +26,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import com.samskivert.jdbc.depot.Key.WhereCondition;
import com.samskivert.jdbc.depot.annotation.Computed;
import com.samskivert.jdbc.depot.clause.DeleteClause;
import com.samskivert.jdbc.depot.clause.FieldDefinition;
@@ -48,9 +47,9 @@ import com.samskivert.jdbc.depot.expression.LiteralExp;
import com.samskivert.jdbc.depot.expression.SQLExpression;
import com.samskivert.jdbc.depot.expression.ValueExp;
import com.samskivert.jdbc.depot.operator.Conditionals.Exists;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.jdbc.depot.operator.Conditionals.In;
import com.samskivert.jdbc.depot.operator.Conditionals.IsNull;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.jdbc.depot.operator.Logic.Not;
import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator;
import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator;
@@ -69,7 +68,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (FromOverride override)
throws Exception
{
_builder.append(" from " );
List<Class<? extends PersistentRecord>> from = override.getFromClasses();
@@ -84,7 +82,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (FieldDefinition definition)
throws Exception
{
definition.getDefinition().accept(this);
if (_enableAliasing) {
@@ -93,11 +90,10 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
}
public void visit (WhereCondition<? extends PersistentRecord> whereCondition)
throws Exception
public void visit (Key.WhereCondition<? extends PersistentRecord> whereCondition)
{
Class<? extends PersistentRecord> pClass = whereCondition.getPersistentClass();
String[] keyFields = Key.getKeyFields(pClass);
String[] keyFields = KeyUtil.getKeyFields(pClass);
List<Comparable<?>> values = whereCondition.getValues();
for (int ii = 0; ii < keyFields.length; ii ++) {
if (ii > 0) {
@@ -113,15 +109,13 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
}
public void visit (Key<? extends PersistentRecord> key)
throws Exception
public void visit (WhereClause where)
{
_builder.append(" where ");
key.condition.accept(this);
where.getWhereExpression().accept(this);
}
public void visit (MultiKey<? extends PersistentRecord> key)
throws Exception
{
_builder.append(" where ");
boolean first = true;
@@ -156,7 +150,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (FunctionExp functionExp)
throws Exception
{
_builder.append(functionExp.getFunction());
_builder.append("(");
@@ -171,7 +164,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (MultiOperator multiOperator)
throws Exception
{
SQLExpression[] conditions = multiOperator.getConditions();
for (int ii = 0; ii < conditions.length; ii++) {
@@ -185,7 +177,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (BinaryOperator binaryOperator)
throws Exception
{
_builder.append('(');
binaryOperator.getLeftHandSide().accept(this);
@@ -195,14 +186,12 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (IsNull isNull)
throws Exception
{
isNull.getColumn().accept(this);
_builder.append(" is null");
}
public void visit (In in)
throws Exception
{
in.getColumn().accept(this);
_builder.append(" in (");
@@ -216,17 +205,14 @@ public abstract class BuildVisitor implements ExpressionVisitor
_builder.append(")");
}
public abstract void visit (FullTextMatch match)
throws Exception;
public abstract void visit (FullTextMatch match);
public void visit (ColumnExp columnExp)
throws Exception
{
appendRhsColumn(columnExp.getPersistentClass(), columnExp.getField());
}
public void visit (Not not)
throws Exception
{
_builder.append(" not (");
not.getCondition().accept(this);
@@ -234,7 +220,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (GroupBy groupBy)
throws Exception
{
_builder.append(" group by ");
@@ -248,13 +233,11 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (ForUpdate forUpdate)
throws Exception
{
_builder.append(" for update ");
}
public void visit (OrderBy orderBy)
throws Exception
{
_builder.append(" order by ");
@@ -269,15 +252,7 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
}
public void visit (Where where)
throws Exception
{
_builder.append(" where ");
where.getCondition().accept(this);
}
public void visit (Join join)
throws Exception
{
switch (join.getType()) {
case INNER:
@@ -298,32 +273,27 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (Limit limit)
throws Exception
{
_builder.append(" limit ? offset ? ");
}
public void visit (LiteralExp literalExp)
throws Exception
{
_builder.append(literalExp.getText());
}
public void visit (ValueExp valueExp)
throws Exception
{
_builder.append("?");
}
public void visit (Exists<? extends PersistentRecord> exists)
throws Exception
{
_builder.append("exists ");
exists.getSubClause().accept(this);
}
public void visit (SelectClause<? extends PersistentRecord> selectClause)
throws Exception
{
Class<? extends PersistentRecord> pClass = selectClause.getPersistentClass();
boolean isInner = _innerClause;
@@ -381,7 +351,8 @@ public abstract class BuildVisitor implements ExpressionVisitor
} else if (_types.getTableName(pClass) != null) {
tClass = pClass;
} else {
throw new SQLException("Query on @Computed entity with no FromOverrideClause.");
throw new IllegalStateException(
"Query on @Computed entity with no FromOverrideClause.");
}
_builder.append(" from ");
appendTableName(tClass);
@@ -417,10 +388,10 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (UpdateClause<? extends PersistentRecord> updateClause)
throws Exception
{
if (updateClause.getWhereClause() == null) {
throw new SQLException("I dare not currently perform UPDATE without a WHERE clause.");
throw new IllegalArgumentException(
"I dare not currently perform UPDATE without a WHERE clause.");
}
Class<? extends PersistentRecord> pClass = updateClause.getPersistentClass();
_innerClause = true;
@@ -451,7 +422,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (DeleteClause<? extends PersistentRecord> deleteClause)
throws Exception
{
_builder.append("delete from ");
appendTableName(deleteClause.getPersistentClass());
@@ -462,7 +432,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
}
public void visit (InsertClause<? extends PersistentRecord> insertClause)
throws Exception
{
Class<? extends PersistentRecord> pClass = insertClause.getPersistentClass();
DepotMarshaller<?> marsh = _types.getMarshaller(pClass);
@@ -512,7 +481,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
// We do not prepend this identifier with a table abbreviation, nor do we expand
// field overrides, shadowOf declarations, or the like: it is just a column name.
protected void appendLhsColumn (Class<? extends PersistentRecord> type, String field)
throws Exception
{
DepotMarshaller<?> dm = _types.getMarshaller(type);
if (dm == null) {
@@ -527,7 +495,6 @@ public abstract class BuildVisitor implements ExpressionVisitor
// Appends an expression for the given field on the given persistent record; this can
// appear in a SELECT list, in WHERE clauses, etc, etc.
protected void appendRhsColumn (Class<? extends PersistentRecord> type, String field)
throws Exception
{
DepotMarshaller<?> dm = _types.getMarshaller(type);
if (dm == null) {
@@ -45,6 +45,8 @@ import com.samskivert.jdbc.depot.annotation.Index;
import com.samskivert.jdbc.depot.annotation.TableGenerator;
import com.samskivert.jdbc.depot.annotation.Transient;
import com.samskivert.jdbc.depot.annotation.UniqueConstraint;
import com.samskivert.jdbc.depot.operator.Conditionals;
import com.samskivert.jdbc.depot.operator.Logic;
import com.samskivert.jdbc.ColumnDefinition;
import com.samskivert.jdbc.DatabaseLiaison;
@@ -458,7 +460,7 @@ public class DepotMarshaller<T extends PersistentRecord>
}
throw new SQLException("ResultSet missing field: " + fm.getField().getName());
}
fm.writeToObject(rs, po);
fm.getAndWriteToObject(rs, po);
}
return po;
@@ -22,10 +22,12 @@ package com.samskivert.jdbc.depot;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -41,6 +43,7 @@ import com.samskivert.jdbc.depot.clause.DeleteClause;
import com.samskivert.jdbc.depot.clause.FieldOverride;
import com.samskivert.jdbc.depot.clause.InsertClause;
import com.samskivert.jdbc.depot.clause.QueryClause;
import com.samskivert.jdbc.depot.clause.SelectClause;
import com.samskivert.jdbc.depot.clause.UpdateClause;
import com.samskivert.jdbc.depot.expression.SQLExpression;
import com.samskivert.jdbc.depot.expression.ValueExp;
@@ -399,7 +402,7 @@ public abstract class DepotRepository
protected <T extends PersistentRecord> int updatePartial (Key<T> key, Object... fieldsValues)
throws DatabaseException
{
return updatePartial(key.condition.getPersistentClass(), key, key, fieldsValues);
return updatePartial(key.getPersistentClass(), key, key, fieldsValues);
}
/**
@@ -699,21 +702,55 @@ public abstract class DepotRepository
return deleteAll(type, primaryKey, primaryKey);
}
/**
* Deletes all persistent objects from the database that match the supplied where clause.
*
* @return the number of rows deleted by this action.
*/
protected <T extends PersistentRecord> int deleteAll (Class<T> type, final WhereClause where)
throws DatabaseException
{
// first look up the primary keys for all the rows that match our where clause
final Set<Key<T>> keys = new HashSet<Key<T>>();
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
final SQLBuilder fbuilder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, where));
fbuilder.newQuery(new SelectClause<T>(type, marsh.getPrimaryKeyFields(), where));
_ctx.invoke(new Modifier(null) {
@Override
public int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
PreparedStatement stmt = fbuilder.prepare(conn);
try {
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
keys.add(marsh.makePrimaryKey(rs));
}
return 0;
} finally {
JDBCUtil.close(stmt);
}
}
});
// now delete using that primary key set
PrimaryKeySet<T> pwhere = new PrimaryKeySet<T>(type, keys);
return deleteAll(type, pwhere, pwhere);
}
/**
* Deletes all persistent objects from the database that match the supplied key.
*
* @return the number of rows deleted by this action.
*/
protected <T extends PersistentRecord> int deleteAll (
Class<T> type, final WhereClause key, CacheInvalidator invalidator)
Class<T> type, final WhereClause where, CacheInvalidator invalidator)
throws DatabaseException
{
if (invalidator instanceof ValidatingCacheInvalidator) {
((ValidatingCacheInvalidator)invalidator).validateFlushType(type); // sanity check
}
key.validateQueryType(type); // and another
where.validateQueryType(type); // and another
DeleteClause<T> delete = new DeleteClause<T>(type, key);
DeleteClause<T> delete = new DeleteClause<T>(type, where);
final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, delete));
builder.newQuery(delete);
@@ -161,10 +161,10 @@ public abstract class FieldMarshaller<T>
}
/**
* Reads and returns this field from the result set.
* Reads this field from the given persistent object.
*/
public abstract T getFromSet (ResultSet rs)
throws SQLException;
public abstract T getFromObject (Object po)
throws IllegalArgumentException, IllegalAccessException;
/**
* Sets the specified column of the given prepared statement to the given value.
@@ -173,10 +173,20 @@ public abstract class FieldMarshaller<T>
throws SQLException;
/**
* Reads this field from the given persistent object.
* Reads the value of our field from the supplied persistent object and sets that value into
* the specified column of the supplied prepared statement.
*/
public abstract T getFromObject (Object po)
throws IllegalArgumentException, IllegalAccessException;
public void getAndWriteToStatement (PreparedStatement ps, int column, Object po)
throws SQLException, IllegalAccessException
{
writeToStatement(ps, column, getFromObject(po));
}
/**
* Reads and returns this field from the result set.
*/
public abstract T getFromSet (ResultSet rs)
throws SQLException;
/**
* Writes the given value to the given persistent value.
@@ -185,20 +195,10 @@ public abstract class FieldMarshaller<T>
throws IllegalArgumentException, IllegalAccessException;
/**
* Reads the value of our field from the persistent object and sets that
* value into the specified column of the supplied prepared statement.
* Reads the specified column from the supplied result set and writes it to the appropriate
* field of the persistent object.
*/
public void readFromObject (Object po, PreparedStatement ps, int column)
throws SQLException, IllegalAccessException
{
writeToStatement(ps, column, getFromObject(po));
}
/**
* Reads the specified column from the supplied result set and writes it to
* the appropriate field of the persistent object.
*/
public void writeToObject (ResultSet rset, Object po)
public void getAndWriteToObject (ResultSet rset, Object po)
throws SQLException, IllegalAccessException
{
writeToObject(po, getFromSet(rset));
@@ -116,12 +116,12 @@ public abstract class FindAllQuery<T extends PersistentRecord>
}
// if we're fetching a huge number of records, we have to do it in multiple queries
if (fetchKeys.size() > MAX_IN_KEYS) {
if (fetchKeys.size() > In.MAX_KEYS) {
int keyCount = fetchKeys.size();
do {
Set<Key<T>> keys = new HashSet<Key<T>>();
Iterator<Key<T>> iter = fetchKeys.iterator();
for (int ii = 0; ii < Math.min(keyCount, MAX_IN_KEYS); ii++) {
for (int ii = 0; ii < Math.min(keyCount, In.MAX_KEYS); ii++) {
keys.add(iter.next());
iter.remove();
}
@@ -146,33 +146,9 @@ public abstract class FindAllQuery<T extends PersistentRecord>
protected void loadRecords (Connection conn, Set<Key<T>> keys, Map<Key<T>, T> entities)
throws SQLException
{
SQLExpression condition;
if (_marsh.getPrimaryKeyFields().length == 1) {
// Single-column keys result in the compact IN(keyVal1, keyVal2, ...)
Comparable<?>[] keyFieldValues = new Comparable<?>[keys.size()];
int ii = 0;
for (Key<T> key : keys) {
keyFieldValues[ii ++] = key.condition.getValues().get(0);
}
condition = new In(_type, _marsh.getPrimaryKeyFields()[0], keyFieldValues);
} else {
// Multi-column keys result in OR'd AND's, of unknown efficiency (TODO check).
SQLExpression[] keyArray = new SQLExpression[keys.size()];
int ii = 0;
for (Key<T> key : keys) {
keyArray[ii ++] = key.condition;
}
condition = new Or(keyArray);
}
Where keyWhere = new Where(condition);
// finally build the new query
_builder.newQuery(new SelectClause<T>(_type, _marsh.getFieldNames(), keyWhere));
_builder.newQuery(new SelectClause<T>(_type, _marsh.getFieldNames(),
new PrimaryKeySet<T>(_type, keys)));
PreparedStatement stmt = _builder.prepare(conn);
// and execute it
try {
ResultSet rs = stmt.executeQuery();
int cnt = 0, dups = 0;
@@ -275,7 +251,4 @@ public abstract class FindAllQuery<T extends PersistentRecord>
protected SQLBuilder _builder;
protected DepotMarshaller<T> _marsh;
protected Class<T> _type;
/** The maximum number of keys allowed in an IN() clause. */
protected static final int MAX_IN_KEYS = Short.MAX_VALUE;
}
+37 -42
View File
@@ -24,7 +24,6 @@ import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
@@ -55,7 +54,6 @@ public class Key<T extends PersistentRecord> extends WhereClause
// from SQLExpression
public void accept (ExpressionVisitor builder)
throws Exception
{
builder.visit(this);
}
@@ -96,9 +94,6 @@ public class Key<T extends PersistentRecord> extends WhereClause
protected ArrayList<Comparable<?>> _values; // List is not Serializable
}
/** The expression that identifies our row. */
public final WhereCondition<T> condition;
/**
* Constructs a new single-column {@code Key} with the given value.
*/
@@ -141,7 +136,7 @@ public class Key<T extends PersistentRecord> extends WhereClause
}
// look up the cached primary key fields for this object
String[] keyFields = getKeyFields(pClass);
String[] keyFields = KeyUtil.getKeyFields(pClass);
// now extract the values in field order and ensure none are extra or missing
ArrayList<Comparable<?>> newValues = new ArrayList<Comparable<?>>();
@@ -165,18 +160,39 @@ public class Key<T extends PersistentRecord> extends WhereClause
"Non-key columns given: " + StringUtil.join(map.keySet().toArray(), ", "));
}
condition = new WhereCondition<T>(pClass, newValues);
_condition = new WhereCondition<T>(pClass, newValues);
}
/**
* Returns the persistent class for which we represent a key.
*/
public Class<T> getPersistentClass ()
{
return _condition.getPersistentClass();
}
/**
* Returns the values bound to this key.
*/
public ArrayList<Comparable<?>> getValues ()
{
return _condition.getValues();
}
// from WhereClause
public SQLExpression getWhereExpression ()
{
return _condition;
}
// from SQLExpression
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
{
classSet.add(condition.getPersistentClass());
classSet.add(_condition.getPersistentClass());
}
// from SQLExpression
public void accept (ExpressionVisitor builder)
throws Exception
{
builder.visit(this);
}
@@ -184,23 +200,23 @@ public class Key<T extends PersistentRecord> extends WhereClause
// from CacheKey
public String getCacheId ()
{
return condition.getPersistentClass().getName();
return _condition.getPersistentClass().getName();
}
// from CacheKey
public Serializable getCacheKey ()
{
return condition.getValues();
return _condition.getValues();
}
// from ValidatingCacheInvalidator
public void validateFlushType (Class<?> pClass)
{
if (!pClass.equals(condition.getPersistentClass())) {
if (!pClass.equals(_condition.getPersistentClass())) {
throw new IllegalArgumentException(
"Class mismatch between persistent record and cache invalidator " +
"[record=" + pClass.getSimpleName() +
", invtype=" + condition.getPersistentClass().getSimpleName() + "].");
", invtype=" + _condition.getPersistentClass().getSimpleName() + "].");
}
}
@@ -214,7 +230,7 @@ public class Key<T extends PersistentRecord> extends WhereClause
public void validateQueryType (Class<?> pClass)
{
super.validateQueryType(pClass);
validateTypesMatch(pClass, condition.getPersistentClass());
validateTypesMatch(pClass, _condition.getPersistentClass());
}
@Override
@@ -226,52 +242,31 @@ public class Key<T extends PersistentRecord> extends WhereClause
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return condition.equals(((Key<?>) obj).condition);
return _condition.equals(((Key<?>) obj)._condition);
}
@Override
public int hashCode ()
{
return condition.hashCode();
return _condition.hashCode();
}
@Override
public String toString ()
{
StringBuilder builder = new StringBuilder(condition.getPersistentClass().getSimpleName());
StringBuilder builder = new StringBuilder(_condition.getPersistentClass().getSimpleName());
builder.append("(");
String[] keyFields = getKeyFields(condition.getPersistentClass());
String[] keyFields = KeyUtil.getKeyFields(_condition.getPersistentClass());
for (int ii = 0; ii < keyFields.length; ii ++) {
if (ii > 0) {
builder.append(", ");
}
builder.append(keyFields[ii]).append("=").append(condition.getValues().get(ii));
builder.append(keyFields[ii]).append("=").append(_condition.getValues().get(ii));
}
builder.append(")");
return builder.toString();
}
/**
* Returns an array containing the names of the primary key fields for the supplied persistent
* class. The values are introspected and cached for the lifetime of the VM.
*/
protected static String[] getKeyFields (Class<?> pClass)
{
String[] fields = _keyFields.get(pClass);
if (fields == null) {
List<String> kflist = new ArrayList<String>();
for (Field field : pClass.getFields()) {
// look for @Id fields
if (field.getAnnotation(Id.class) != null) {
kflist.add(field.getName());
}
}
_keyFields.put(pClass, fields = kflist.toArray(new String[kflist.size()]));
}
return fields;
}
/** A (never expiring) cache of primary key field names for all persistent classes (of which
* there are merely dozens, so we don't need to worry about expiring). */
protected static HashMap<Class<?>,String[]> _keyFields = new HashMap<Class<?>,String[]>();
/** The expression that identifies our row. */
protected final WhereCondition<T> _condition;
}
@@ -0,0 +1,59 @@
//
// $Id$
//
// samskivert library - useful routines for java programs
// Copyright (C) 2001-2008 Michael Bayne
//
// 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.jdbc.depot;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.samskivert.jdbc.depot.annotation.Id;
/**
* Simple utility methods used by {@link Key} and {@link PrimaryKeySet}.
*/
public class KeyUtil
{
/**
* Returns an array containing the names of the primary key fields for the supplied persistent
* class. The values are introspected and cached for the lifetime of the VM.
*/
public static String[] getKeyFields (Class<?> pClass)
{
String[] fields = _keyFields.get(pClass);
if (fields == null) {
List<String> kflist = new ArrayList<String>();
for (Field field : pClass.getFields()) {
// look for @Id fields
if (field.getAnnotation(Id.class) != null) {
kflist.add(field.getName());
}
}
_keyFields.put(pClass, fields = kflist.toArray(new String[kflist.size()]));
}
return fields;
}
/** A (never expiring) cache of primary key field names for all persistent classes (of which
* there are merely dozens, so we don't need to worry about expiring). */
protected static Map<Class<?>,String[]> _keyFields = new HashMap<Class<?>,String[]>();
}
@@ -26,6 +26,7 @@ import java.util.Map;
import com.samskivert.jdbc.depot.clause.Where;
import com.samskivert.jdbc.depot.expression.ExpressionVisitor;
import com.samskivert.jdbc.depot.expression.SQLExpression;
/**
* A special form of {@link Where} clause that specifies an explicit range of database rows. It
@@ -101,8 +102,14 @@ public class MultiKey<T extends PersistentRecord> extends WhereClause
return _mValues;
}
// from WhereClause
public SQLExpression getWhereExpression ()
{
throw new RuntimeException("Not used");
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -57,7 +57,6 @@ public class MySQLBuilder
public class MSBuildVisitor extends BuildVisitor
{
@Override public void visit (FullTextMatch match)
throws Exception
{
_builder.append("match(");
Class<? extends PersistentRecord> pClass = match.getPersistentRecord();
@@ -73,7 +72,6 @@ public class MySQLBuilder
}
@Override public void visit (DeleteClause<? extends PersistentRecord> deleteClause)
throws Exception
{
_builder.append("delete from ");
appendTableName(deleteClause.getPersistentClass());
@@ -90,7 +88,6 @@ public class MySQLBuilder
}
public void visit (EpochSeconds epochSeconds)
throws Exception
{
_builder.append("unix_timestamp(");
epochSeconds.getArgument().accept(this);
@@ -120,15 +117,17 @@ public class MySQLBuilder
public class MSBindVisitor extends BindVisitor
{
protected MSBindVisitor (DepotTypes types, PreparedStatement stmt)
{
protected MSBindVisitor (DepotTypes types, PreparedStatement stmt) {
super(types, stmt);
}
@Override public void visit (FullTextMatch match)
throws Exception
{
_stmt.setString(_argIdx ++, match.getQuery());
@Override public void visit (FullTextMatch match) {
try {
_stmt.setString(_argIdx++, match.getQuery());
} catch (SQLException sqe) {
throw new DatabaseException("Failed to configure full-text match column " +
"[idx=" + (_argIdx-1) + ", match=" + match + "]", sqe);
}
}
}
@@ -59,14 +59,12 @@ public class PostgreSQLBuilder
public class PGBuildVisitor extends BuildVisitor
{
@Override public void visit (FullTextMatch match)
throws Exception
{
appendIdentifier("ftsCol_" + match.getName());
_builder.append(" @@ TO_TSQUERY('default', ?)");
}
public void visit (EpochSeconds epochSeconds)
throws Exception
{
_builder.append("date_part('epoch', ");
epochSeconds.getArgument().accept(this);
@@ -86,25 +84,26 @@ public class PostgreSQLBuilder
public class PGBindVisitor extends BindVisitor
{
@Override public void visit (FullTextMatch match)
throws Exception
{
@Override public void visit (FullTextMatch match) {
// The tsearch2 engine takes queries on the form
// (foo&bar)|goop
// so in this first simple implementation, we just take the user query, chop it into
// words by space/punctuation and 'or' those together like so:
// 'ho! who goes there?' -> 'ho|who|goes|there'
String[] searchTerms = match.getQuery().toLowerCase().split("\\W+");
if (searchTerms.length > 0 && searchTerms[0].length() == 0) {
searchTerms = ArrayUtil.splice(searchTerms, 0, 1);
}
String query = StringUtil.join(searchTerms, "|");
_stmt.setString(_argIdx ++, query);
try {
_stmt.setString(_argIdx++, query);
} catch (SQLException sqe) {
throw new DatabaseException("Failed to configure full-text match column " +
"[idx=" + (_argIdx-1) + ", query=" + query + "]", sqe);
}
}
protected PGBindVisitor (DepotTypes types, PreparedStatement stmt)
{
protected PGBindVisitor (DepotTypes types, PreparedStatement stmt) {
super(types, stmt);
}
}
@@ -0,0 +1,153 @@
//
// $Id$
//
// samskivert library - useful routines for java programs
// Copyright (C) 2001-2008 Michael Bayne
//
// 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.jdbc.depot;
import java.util.Collection;
import java.util.Set;
import com.samskivert.jdbc.depot.expression.ExpressionVisitor;
import com.samskivert.jdbc.depot.expression.LiteralExp;
import com.samskivert.jdbc.depot.expression.SQLExpression;
import com.samskivert.jdbc.depot.operator.Conditionals;
import com.samskivert.jdbc.depot.operator.Logic;
/**
* Contains a set of primary keys that match a set of persistent records. This is used internally
* in Depot when decomposing queries into two parts: first a query for the primary keys that
* identify the records that match a free-form query and then another query that operates on the
* previously identified keys. The keys obtained in the first query are used to create a
* PrimaryKeySet and modifications and deletons using this set will automatically flush the
* appropriate records from the cache.
*/
public class PrimaryKeySet<T extends PersistentRecord> extends WhereClause
implements SQLExpression, ValidatingCacheInvalidator
{
/**
* Creates a set from the supplied primary keys.
*/
public PrimaryKeySet (Class<T> pClass, Set<Key<T>> keys)
{
_pClass = pClass;
_keys = keys;
String[] keyFields = KeyUtil.getKeyFields(pClass);
if (keys.size() == 0) {
_condition = new LiteralExp("false");
} else if (keyFields.length == 1) {
if (keys.size() > Conditionals.In.MAX_KEYS) {
throw new IllegalArgumentException("Cannot create where clause for more than " +
Conditionals.In.MAX_KEYS + " at a time.");
}
// Single-column keys result in the compact IN(keyVal1, keyVal2, ...)
Comparable<?>[] keyFieldValues = new Comparable<?>[keys.size()];
int ii = 0;
for (Key<T> key : keys) {
keyFieldValues[ii++] = key.getValues().get(0);
}
_condition = new Conditionals.In(pClass, keyFields[0], keyFieldValues);
} else {
// TODO: is there a maximum size of an or query? 32768?
// Multi-column keys result in OR'd AND's, of unknown efficiency (TODO check).
SQLExpression[] keyArray = new SQLExpression[keys.size()];
int ii = 0;
for (Key<T> key : keys) {
keyArray[ii ++] = key.getWhereExpression();
}
_condition = new Logic.Or(keyArray);
}
}
// from WhereClause
public SQLExpression getWhereExpression ()
{
return _condition;
}
// from SQLExpression
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
{
classSet.add(_pClass);
}
// from SQLExpression
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
// from ValidatingCacheInvalidator
public void validateFlushType (Class<?> pClass)
{
if (!pClass.equals(_pClass)) {
throw new IllegalArgumentException(
"Class mismatch between persistent record and cache invalidator " +
"[record=" + pClass.getSimpleName() + ", invtype=" + _pClass.getSimpleName() + "].");
}
}
// from CacheInvalidator
public void invalidate (PersistenceContext ctx)
{
for (Key<T> key : _keys) {
ctx.cacheInvalidate(key);
}
}
@Override // from WhereClause
public void validateQueryType (Class<?> pClass)
{
super.validateQueryType(pClass);
validateTypesMatch(pClass, _pClass);
}
@Override
public boolean equals (Object obj)
{
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return _condition.equals(((Key<?>) obj)._condition);
}
@Override
public int hashCode ()
{
return _condition.hashCode();
}
@Override
public String toString ()
{
return _keys.toString();
}
protected Class<T> _pClass;
protected Set<Key<T>> _keys;
protected SQLExpression _condition;
}
@@ -58,12 +58,7 @@ public abstract class SQLBuilder
{
_clause = clause;
_buildVisitor = getBuildVisitor();
try {
_clause.accept(_buildVisitor);
} catch (Exception e) {
throw new RuntimeException("Failed to build SQL", e);
}
_clause.accept(_buildVisitor);
}
/**
@@ -80,16 +75,10 @@ public abstract class SQLBuilder
if (_buildVisitor == null) {
throw new IllegalArgumentException("Cannot prepare query until it's been built.");
}
PreparedStatement stmt = conn.prepareStatement(_buildVisitor.getQuery());
_bindVisitor = getBindVisitor(stmt);
try {
_clause.accept(_bindVisitor);
} catch (SQLException se) {
throw se;
} catch (Exception e) {
throw new RuntimeException("Failed to find SQL parameters", e);
}
_clause.accept(_bindVisitor);
if (PersistenceContext.DEBUG) {
log.info("SQL: " + stmt.toString());
@@ -21,12 +21,18 @@
package com.samskivert.jdbc.depot;
import com.samskivert.jdbc.depot.clause.QueryClause;
import com.samskivert.jdbc.depot.expression.SQLExpression;
/**
* Currently only exists as a type without any functionality of its own.
*/
public abstract class WhereClause extends QueryClause
{
/**
* Returns the condition associated with this where clause.
*/
public abstract SQLExpression getWhereExpression ();
/**
* Validates that the supplied persistent record type is the type matched by this where clause.
* Not all clauses will be able to perform this validation, but those that can, should do so to
@@ -54,7 +54,7 @@ public class DeleteClause<T extends PersistentRecord> extends QueryClause
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -76,7 +76,6 @@ public class FieldDefinition extends QueryClause
// from SQLExpression
public void accept (ExpressionVisitor visitor)
throws Exception
{
visitor.visit(this);
}
@@ -31,7 +31,7 @@ import com.samskivert.jdbc.depot.expression.ExpressionVisitor;
public class ForUpdate extends QueryClause
{
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -62,7 +62,6 @@ public class FromOverride extends QueryClause
// from SQLExpression
public void accept (ExpressionVisitor builder)
throws Exception
{
builder.visit(this);
}
@@ -42,7 +42,7 @@ public class GroupBy extends QueryClause
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -62,7 +62,7 @@ public class InsertClause<T extends PersistentRecord> extends QueryClause
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -80,7 +80,7 @@ public class Join extends QueryClause
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -47,7 +47,7 @@ public class Limit extends QueryClause
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -76,7 +76,7 @@ public class OrderBy extends QueryClause
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -195,7 +195,7 @@ public class SelectClause<T extends PersistentRecord> extends QueryClause
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -92,7 +92,7 @@ public class UpdateClause<T extends PersistentRecord> extends QueryClause
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -67,13 +67,14 @@ public class Where extends WhereClause
_condition = condition;
}
public SQLExpression getCondition ()
// from WhereClause
public SQLExpression getWhereExpression ()
{
return _condition;
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -38,7 +38,7 @@ public class ColumnExp
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -39,7 +39,6 @@ public class EpochSeconds implements SQLExpression
// from SQLExpression
public void accept (ExpressionVisitor builder)
throws Exception
{
builder.visit(this);
}
@@ -20,10 +20,10 @@
package com.samskivert.jdbc.depot.expression;
import com.samskivert.jdbc.depot.Key.WhereCondition;
import com.samskivert.jdbc.depot.Key;
import com.samskivert.jdbc.depot.MultiKey;
import com.samskivert.jdbc.depot.PersistentRecord;
import com.samskivert.jdbc.depot.WhereClause;
import com.samskivert.jdbc.depot.clause.DeleteClause;
import com.samskivert.jdbc.depot.clause.FieldDefinition;
@@ -51,58 +51,30 @@ import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator;
*/
public interface ExpressionVisitor
{
public void visit (FieldDefinition fieldOverride)
throws Exception;
public void visit (WhereCondition<? extends PersistentRecord> whereCondition)
throws Exception;
public void visit (Key<? extends PersistentRecord> key)
throws Exception;
public void visit (MultiKey<? extends PersistentRecord> key)
throws Exception;
public void visit (FunctionExp functionExp)
throws Exception;
public void visit (EpochSeconds epochSeconds)
throws Exception;
public void visit (FromOverride fromOverride)
throws Exception;
public void visit (MultiOperator multiOperator)
throws Exception;
public void visit (BinaryOperator binaryOperator)
throws Exception;
public void visit (IsNull isNull)
throws Exception;
public void visit (In in)
throws Exception;
public void visit (FullTextMatch match)
throws Exception;
public void visit (ColumnExp columnExp)
throws Exception;
public void visit (Not not)
throws Exception;
public void visit (GroupBy groupBy)
throws Exception;
public void visit (ForUpdate forUpdate)
throws Exception;
public void visit (OrderBy orderBy)
throws Exception;
public void visit (Where where)
throws Exception;
public void visit (Join join)
throws Exception;
public void visit (Limit limit)
throws Exception;
public void visit (LiteralExp literalExp)
throws Exception;
public void visit (ValueExp valueExp)
throws Exception;
public void visit (Exists<? extends PersistentRecord> exists)
throws Exception;
public void visit (SelectClause<? extends PersistentRecord> selectClause)
throws Exception;
public void visit (UpdateClause<? extends PersistentRecord> updateClause)
throws Exception;
public void visit (DeleteClause<? extends PersistentRecord> deleteClause)
throws Exception;
public void visit (InsertClause<? extends PersistentRecord> insertClause)
throws Exception;
public void visit (FieldDefinition fieldOverride);
public void visit (Key.WhereCondition<? extends PersistentRecord> whereCondition);
public void visit (MultiKey<? extends PersistentRecord> key);
public void visit (FunctionExp functionExp);
public void visit (EpochSeconds epochSeconds);
public void visit (FromOverride fromOverride);
public void visit (MultiOperator multiOperator);
public void visit (BinaryOperator binaryOperator);
public void visit (IsNull isNull);
public void visit (In in);
public void visit (FullTextMatch match);
public void visit (ColumnExp columnExp);
public void visit (Not not);
public void visit (GroupBy groupBy);
public void visit (ForUpdate forUpdate);
public void visit (OrderBy orderBy);
public void visit (WhereClause where);
public void visit (Join join);
public void visit (Limit limit);
public void visit (LiteralExp literalExp);
public void visit (ValueExp valueExp);
public void visit (Exists<? extends PersistentRecord> exists);
public void visit (SelectClause<? extends PersistentRecord> selectClause);
public void visit (UpdateClause<? extends PersistentRecord> updateClause);
public void visit (DeleteClause<? extends PersistentRecord> deleteClause);
public void visit (InsertClause<? extends PersistentRecord> insertClause);
}
@@ -40,7 +40,6 @@ public class FunctionExp implements SQLExpression
// from SQLExpression
public void accept (ExpressionVisitor builder)
throws Exception
{
builder.visit(this);
}
@@ -37,7 +37,7 @@ public class LiteralExp
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -36,8 +36,7 @@ public interface SQLExpression
*
* @see SQLBuilder
*/
public void accept (ExpressionVisitor builder)
throws Exception;
public void accept (ExpressionVisitor builder);
/**
* Adds all persistent classes that are brought into the SQL context by this clause: FROM
@@ -36,7 +36,7 @@ public class ValueExp
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -59,7 +59,7 @@ public abstract class Conditionals
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -190,6 +190,9 @@ public abstract class Conditionals
public static class In
implements SQLOperator
{
/** The maximum number of keys allowed in an IN() clause. */
public static final int MAX_KEYS = Short.MAX_VALUE;
public In (Class<? extends PersistentRecord> pClass, String pColumn, Comparable<?>... values)
{
this(new ColumnExp(pClass, pColumn), values);
@@ -226,7 +229,7 @@ public abstract class Conditionals
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -268,7 +271,7 @@ public abstract class Conditionals
_clause = clause;
}
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -316,7 +319,7 @@ public abstract class Conditionals
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -91,7 +91,7 @@ public abstract class Logic
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -46,7 +46,7 @@ public interface SQLOperator extends SQLExpression
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}
@@ -89,7 +89,7 @@ public interface SQLOperator extends SQLExpression
}
// from SQLExpression
public void accept (ExpressionVisitor builder) throws Exception
public void accept (ExpressionVisitor builder)
{
builder.visit(this);
}