diff --git a/src/java/com/samskivert/jdbc/depot/BindVisitor.java b/src/java/com/samskivert/jdbc/depot/BindVisitor.java index 563adf9..aa4b689 100644 --- a/src/java/com/samskivert/jdbc/depot/BindVisitor.java +++ b/src/java/com/samskivert/jdbc/depot/BindVisitor.java @@ -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 whereCondition) - throws Exception { for (Comparable value : whereCondition.getValues()) { if (value != null) { @@ -81,14 +82,7 @@ public class BindVisitor implements ExpressionVisitor } } - public void visit (Key key) - throws Exception - { - key.condition.accept(this); - } - public void visit (MultiKey key) - throws Exception { for (Map.Entry> 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 exists) - throws Exception { exists.getSubClause().accept(this); } public void visit (SelectClause selectClause) - throws Exception { for (Join clause : selectClause.getJoinClauses()) { clause.accept(this); @@ -222,16 +217,21 @@ public class BindVisitor implements ExpressionVisitor } } - public void visit (UpdateClause updateClause) throws Exception + public void visit (UpdateClause 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 deleteClause) throws Exception - { - deleteClause.getWhereClause().accept(this); - } - - public void visit (InsertClause insertClause) throws Exception + public void visit (InsertClause insertClause) { DepotMarshaller marsh = _types.getMarshaller(insertClause.getPersistentClass()); - Object pojo = insertClause.getPojo(); Set 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 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); } } diff --git a/src/java/com/samskivert/jdbc/depot/BuildVisitor.java b/src/java/com/samskivert/jdbc/depot/BuildVisitor.java index 10ce038..ad7ded6 100644 --- a/src/java/com/samskivert/jdbc/depot/BuildVisitor.java +++ b/src/java/com/samskivert/jdbc/depot/BuildVisitor.java @@ -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> 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 whereCondition) - throws Exception + public void visit (Key.WhereCondition whereCondition) { Class pClass = whereCondition.getPersistentClass(); - String[] keyFields = Key.getKeyFields(pClass); + String[] keyFields = KeyUtil.getKeyFields(pClass); List> 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 key) - throws Exception + public void visit (WhereClause where) { _builder.append(" where "); - key.condition.accept(this); + where.getWhereExpression().accept(this); } public void visit (MultiKey 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 exists) - throws Exception { _builder.append("exists "); exists.getSubClause().accept(this); } public void visit (SelectClause selectClause) - throws Exception { Class 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 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 pClass = updateClause.getPersistentClass(); _innerClause = true; @@ -451,7 +422,6 @@ public abstract class BuildVisitor implements ExpressionVisitor } public void visit (DeleteClause deleteClause) - throws Exception { _builder.append("delete from "); appendTableName(deleteClause.getPersistentClass()); @@ -462,7 +432,6 @@ public abstract class BuildVisitor implements ExpressionVisitor } public void visit (InsertClause insertClause) - throws Exception { Class 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 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 type, String field) - throws Exception { DepotMarshaller dm = _types.getMarshaller(type); if (dm == null) { diff --git a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java index 716b999..c61a41e 100644 --- a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java +++ b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java @@ -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 } throw new SQLException("ResultSet missing field: " + fm.getField().getName()); } - fm.writeToObject(rs, po); + fm.getAndWriteToObject(rs, po); } return po; diff --git a/src/java/com/samskivert/jdbc/depot/DepotRepository.java b/src/java/com/samskivert/jdbc/depot/DepotRepository.java index ff54738..adf3932 100644 --- a/src/java/com/samskivert/jdbc/depot/DepotRepository.java +++ b/src/java/com/samskivert/jdbc/depot/DepotRepository.java @@ -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 int updatePartial (Key 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 int deleteAll (Class type, final WhereClause where) + throws DatabaseException + { + // first look up the primary keys for all the rows that match our where clause + final Set> keys = new HashSet>(); + final DepotMarshaller marsh = _ctx.getMarshaller(type); + final SQLBuilder fbuilder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, where)); + fbuilder.newQuery(new SelectClause(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 pwhere = new PrimaryKeySet(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 int deleteAll ( - Class type, final WhereClause key, CacheInvalidator invalidator) + Class 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 delete = new DeleteClause(type, key); + DeleteClause delete = new DeleteClause(type, where); final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, delete)); builder.newQuery(delete); diff --git a/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java b/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java index 3d7b672..9ec2edf 100644 --- a/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java +++ b/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java @@ -161,10 +161,10 @@ public abstract class FieldMarshaller } /** - * 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 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 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)); diff --git a/src/java/com/samskivert/jdbc/depot/FindAllQuery.java b/src/java/com/samskivert/jdbc/depot/FindAllQuery.java index 6ee84cb..fa45f57 100644 --- a/src/java/com/samskivert/jdbc/depot/FindAllQuery.java +++ b/src/java/com/samskivert/jdbc/depot/FindAllQuery.java @@ -116,12 +116,12 @@ public abstract class FindAllQuery } // 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> keys = new HashSet>(); Iterator> 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 protected void loadRecords (Connection conn, Set> keys, Map, 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 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 key : keys) { - keyArray[ii ++] = key.condition; - } - condition = new Or(keyArray); - } - - Where keyWhere = new Where(condition); - // finally build the new query - _builder.newQuery(new SelectClause(_type, _marsh.getFieldNames(), keyWhere)); + _builder.newQuery(new SelectClause(_type, _marsh.getFieldNames(), + new PrimaryKeySet(_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 protected SQLBuilder _builder; protected DepotMarshaller _marsh; protected Class _type; - - /** The maximum number of keys allowed in an IN() clause. */ - protected static final int MAX_IN_KEYS = Short.MAX_VALUE; } diff --git a/src/java/com/samskivert/jdbc/depot/Key.java b/src/java/com/samskivert/jdbc/depot/Key.java index 0b748a7..3793efc 100644 --- a/src/java/com/samskivert/jdbc/depot/Key.java +++ b/src/java/com/samskivert/jdbc/depot/Key.java @@ -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 extends WhereClause // from SQLExpression public void accept (ExpressionVisitor builder) - throws Exception { builder.visit(this); } @@ -96,9 +94,6 @@ public class Key extends WhereClause protected ArrayList> _values; // List is not Serializable } - /** The expression that identifies our row. */ - public final WhereCondition condition; - /** * Constructs a new single-column {@code Key} with the given value. */ @@ -141,7 +136,7 @@ public class Key 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> newValues = new ArrayList>(); @@ -165,18 +160,39 @@ public class Key extends WhereClause "Non-key columns given: " + StringUtil.join(map.keySet().toArray(), ", ")); } - condition = new WhereCondition(pClass, newValues); + _condition = new WhereCondition(pClass, newValues); + } + + /** + * Returns the persistent class for which we represent a key. + */ + public Class getPersistentClass () + { + return _condition.getPersistentClass(); + } + + /** + * Returns the values bound to this key. + */ + public ArrayList> getValues () + { + return _condition.getValues(); + } + + // from WhereClause + public SQLExpression getWhereExpression () + { + return _condition; } // from SQLExpression public void addClasses (Collection> 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 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 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 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 kflist = new ArrayList(); - 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,String[]> _keyFields = new HashMap,String[]>(); + /** The expression that identifies our row. */ + protected final WhereCondition _condition; } diff --git a/src/java/com/samskivert/jdbc/depot/KeyUtil.java b/src/java/com/samskivert/jdbc/depot/KeyUtil.java new file mode 100644 index 0000000..69aea6e --- /dev/null +++ b/src/java/com/samskivert/jdbc/depot/KeyUtil.java @@ -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 kflist = new ArrayList(); + 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,String[]> _keyFields = new HashMap,String[]>(); +} diff --git a/src/java/com/samskivert/jdbc/depot/MultiKey.java b/src/java/com/samskivert/jdbc/depot/MultiKey.java index 3e796e0..3b1d74f 100644 --- a/src/java/com/samskivert/jdbc/depot/MultiKey.java +++ b/src/java/com/samskivert/jdbc/depot/MultiKey.java @@ -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 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); } diff --git a/src/java/com/samskivert/jdbc/depot/MySQLBuilder.java b/src/java/com/samskivert/jdbc/depot/MySQLBuilder.java index befa693..16937a2 100644 --- a/src/java/com/samskivert/jdbc/depot/MySQLBuilder.java +++ b/src/java/com/samskivert/jdbc/depot/MySQLBuilder.java @@ -57,7 +57,6 @@ public class MySQLBuilder public class MSBuildVisitor extends BuildVisitor { @Override public void visit (FullTextMatch match) - throws Exception { _builder.append("match("); Class pClass = match.getPersistentRecord(); @@ -73,7 +72,6 @@ public class MySQLBuilder } @Override public void visit (DeleteClause 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); + } } } diff --git a/src/java/com/samskivert/jdbc/depot/PostgreSQLBuilder.java b/src/java/com/samskivert/jdbc/depot/PostgreSQLBuilder.java index d2cb407..1d103a0 100644 --- a/src/java/com/samskivert/jdbc/depot/PostgreSQLBuilder.java +++ b/src/java/com/samskivert/jdbc/depot/PostgreSQLBuilder.java @@ -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); } } diff --git a/src/java/com/samskivert/jdbc/depot/PrimaryKeySet.java b/src/java/com/samskivert/jdbc/depot/PrimaryKeySet.java new file mode 100644 index 0000000..607c1da --- /dev/null +++ b/src/java/com/samskivert/jdbc/depot/PrimaryKeySet.java @@ -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 extends WhereClause + implements SQLExpression, ValidatingCacheInvalidator +{ + /** + * Creates a set from the supplied primary keys. + */ + public PrimaryKeySet (Class pClass, Set> 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 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 key : keys) { + keyArray[ii ++] = key.getWhereExpression(); + } + _condition = new Logic.Or(keyArray); + } + } + + // from WhereClause + public SQLExpression getWhereExpression () + { + return _condition; + } + + // from SQLExpression + public void addClasses (Collection> 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 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 _pClass; + protected Set> _keys; + protected SQLExpression _condition; +} diff --git a/src/java/com/samskivert/jdbc/depot/SQLBuilder.java b/src/java/com/samskivert/jdbc/depot/SQLBuilder.java index 9e20fe8..4973a90 100644 --- a/src/java/com/samskivert/jdbc/depot/SQLBuilder.java +++ b/src/java/com/samskivert/jdbc/depot/SQLBuilder.java @@ -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()); diff --git a/src/java/com/samskivert/jdbc/depot/WhereClause.java b/src/java/com/samskivert/jdbc/depot/WhereClause.java index ac03734..db6d8eb 100644 --- a/src/java/com/samskivert/jdbc/depot/WhereClause.java +++ b/src/java/com/samskivert/jdbc/depot/WhereClause.java @@ -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 diff --git a/src/java/com/samskivert/jdbc/depot/clause/DeleteClause.java b/src/java/com/samskivert/jdbc/depot/clause/DeleteClause.java index c00167b..a35df28 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/DeleteClause.java +++ b/src/java/com/samskivert/jdbc/depot/clause/DeleteClause.java @@ -54,7 +54,7 @@ public class DeleteClause extends QueryClause } // from SQLExpression - public void accept (ExpressionVisitor builder) throws Exception + public void accept (ExpressionVisitor builder) { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/FieldDefinition.java b/src/java/com/samskivert/jdbc/depot/clause/FieldDefinition.java index b837a82..a5b7f6f 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/FieldDefinition.java +++ b/src/java/com/samskivert/jdbc/depot/clause/FieldDefinition.java @@ -76,7 +76,6 @@ public class FieldDefinition extends QueryClause // from SQLExpression public void accept (ExpressionVisitor visitor) - throws Exception { visitor.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java b/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java index 8ca4917..2adb39e 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java +++ b/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java @@ -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); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java b/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java index a447339..22160d6 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java +++ b/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java @@ -62,7 +62,6 @@ public class FromOverride extends QueryClause // from SQLExpression public void accept (ExpressionVisitor builder) - throws Exception { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java b/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java index 7583e40..497da3b 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java +++ b/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java @@ -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); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/InsertClause.java b/src/java/com/samskivert/jdbc/depot/clause/InsertClause.java index 039d07e..5024b01 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/InsertClause.java +++ b/src/java/com/samskivert/jdbc/depot/clause/InsertClause.java @@ -62,7 +62,7 @@ public class InsertClause extends QueryClause } // from SQLExpression - public void accept (ExpressionVisitor builder) throws Exception + public void accept (ExpressionVisitor builder) { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/Join.java b/src/java/com/samskivert/jdbc/depot/clause/Join.java index 80edd07..4261658 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/Join.java +++ b/src/java/com/samskivert/jdbc/depot/clause/Join.java @@ -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); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/Limit.java b/src/java/com/samskivert/jdbc/depot/clause/Limit.java index 6cc135f..375558a 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/Limit.java +++ b/src/java/com/samskivert/jdbc/depot/clause/Limit.java @@ -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); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java b/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java index 66d92c6..0459c12 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java +++ b/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java @@ -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); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/SelectClause.java b/src/java/com/samskivert/jdbc/depot/clause/SelectClause.java index b081d9f..8dbc79d 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/SelectClause.java +++ b/src/java/com/samskivert/jdbc/depot/clause/SelectClause.java @@ -195,7 +195,7 @@ public class SelectClause extends QueryClause } // from SQLExpression - public void accept (ExpressionVisitor builder) throws Exception + public void accept (ExpressionVisitor builder) { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/UpdateClause.java b/src/java/com/samskivert/jdbc/depot/clause/UpdateClause.java index ba89baa..8d4766a 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/UpdateClause.java +++ b/src/java/com/samskivert/jdbc/depot/clause/UpdateClause.java @@ -92,7 +92,7 @@ public class UpdateClause extends QueryClause } // from SQLExpression - public void accept (ExpressionVisitor builder) throws Exception + public void accept (ExpressionVisitor builder) { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/clause/Where.java b/src/java/com/samskivert/jdbc/depot/clause/Where.java index 19d7588..2392d7c 100644 --- a/src/java/com/samskivert/jdbc/depot/clause/Where.java +++ b/src/java/com/samskivert/jdbc/depot/clause/Where.java @@ -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); } diff --git a/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java b/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java index 68946b7..d10f8fa 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java +++ b/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java @@ -38,7 +38,7 @@ public class ColumnExp } // from SQLExpression - public void accept (ExpressionVisitor builder) throws Exception + public void accept (ExpressionVisitor builder) { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/expression/EpochSeconds.java b/src/java/com/samskivert/jdbc/depot/expression/EpochSeconds.java index e9d164b..94118df 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/EpochSeconds.java +++ b/src/java/com/samskivert/jdbc/depot/expression/EpochSeconds.java @@ -39,7 +39,6 @@ public class EpochSeconds implements SQLExpression // from SQLExpression public void accept (ExpressionVisitor builder) - throws Exception { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/expression/ExpressionVisitor.java b/src/java/com/samskivert/jdbc/depot/expression/ExpressionVisitor.java index 6b7740e..46d3a0b 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/ExpressionVisitor.java +++ b/src/java/com/samskivert/jdbc/depot/expression/ExpressionVisitor.java @@ -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 whereCondition) - throws Exception; - public void visit (Key key) - throws Exception; - public void visit (MultiKey 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 exists) - throws Exception; - public void visit (SelectClause selectClause) - throws Exception; - public void visit (UpdateClause updateClause) - throws Exception; - public void visit (DeleteClause deleteClause) - throws Exception; - public void visit (InsertClause insertClause) - throws Exception; + public void visit (FieldDefinition fieldOverride); + public void visit (Key.WhereCondition whereCondition); + public void visit (MultiKey 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 exists); + public void visit (SelectClause selectClause); + public void visit (UpdateClause updateClause); + public void visit (DeleteClause deleteClause); + public void visit (InsertClause insertClause); } diff --git a/src/java/com/samskivert/jdbc/depot/expression/FunctionExp.java b/src/java/com/samskivert/jdbc/depot/expression/FunctionExp.java index c2834d3..f17864c 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/FunctionExp.java +++ b/src/java/com/samskivert/jdbc/depot/expression/FunctionExp.java @@ -40,7 +40,6 @@ public class FunctionExp implements SQLExpression // from SQLExpression public void accept (ExpressionVisitor builder) - throws Exception { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/expression/LiteralExp.java b/src/java/com/samskivert/jdbc/depot/expression/LiteralExp.java index f15bd70..2092f40 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/LiteralExp.java +++ b/src/java/com/samskivert/jdbc/depot/expression/LiteralExp.java @@ -37,7 +37,7 @@ public class LiteralExp } // from SQLExpression - public void accept (ExpressionVisitor builder) throws Exception + public void accept (ExpressionVisitor builder) { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java b/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java index 0b24ffb..d70ad22 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java +++ b/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java @@ -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 diff --git a/src/java/com/samskivert/jdbc/depot/expression/ValueExp.java b/src/java/com/samskivert/jdbc/depot/expression/ValueExp.java index b306377..080c7b4 100644 --- a/src/java/com/samskivert/jdbc/depot/expression/ValueExp.java +++ b/src/java/com/samskivert/jdbc/depot/expression/ValueExp.java @@ -36,7 +36,7 @@ public class ValueExp } // from SQLExpression - public void accept (ExpressionVisitor builder) throws Exception + public void accept (ExpressionVisitor builder) { builder.visit(this); } diff --git a/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java b/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java index e1915cc..1e083bc 100644 --- a/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java +++ b/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java @@ -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 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); } diff --git a/src/java/com/samskivert/jdbc/depot/operator/Logic.java b/src/java/com/samskivert/jdbc/depot/operator/Logic.java index 53d0450..ee08788 100644 --- a/src/java/com/samskivert/jdbc/depot/operator/Logic.java +++ b/src/java/com/samskivert/jdbc/depot/operator/Logic.java @@ -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); } diff --git a/src/java/com/samskivert/jdbc/depot/operator/SQLOperator.java b/src/java/com/samskivert/jdbc/depot/operator/SQLOperator.java index 5c4ee15..86022bf 100644 --- a/src/java/com/samskivert/jdbc/depot/operator/SQLOperator.java +++ b/src/java/com/samskivert/jdbc/depot/operator/SQLOperator.java @@ -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); }