From b845f7f86bfb7150924d968335535ce26c592b82 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Mon, 11 Sep 2006 04:48:34 +0000 Subject: Switch JDBC repository to use new query engine. --- .../amazon/carbonado/repo/jdbc/JDBCStorage.java | 420 +++++++++++---------- 1 file changed, 212 insertions(+), 208 deletions(-) (limited to 'src/main/java/com/amazon/carbonado/repo/jdbc') diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java index d5b2187..5d4a4a2 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCStorage.java @@ -37,6 +37,7 @@ import org.apache.commons.logging.LogFactory; import com.amazon.carbonado.Cursor; import com.amazon.carbonado.FetchException; +import com.amazon.carbonado.IsolationLevel; import com.amazon.carbonado.PersistException; import com.amazon.carbonado.Query; import com.amazon.carbonado.Repository; @@ -44,6 +45,7 @@ import com.amazon.carbonado.RepositoryException; import com.amazon.carbonado.Storable; import com.amazon.carbonado.Storage; import com.amazon.carbonado.SupportException; +import com.amazon.carbonado.Transaction; import com.amazon.carbonado.Trigger; import com.amazon.carbonado.capability.IndexInfo; @@ -61,19 +63,26 @@ import com.amazon.carbonado.info.OrderedProperty; import com.amazon.carbonado.info.StorableProperty; import com.amazon.carbonado.info.StorablePropertyAdapter; -import com.amazon.carbonado.spi.BaseQuery; -import com.amazon.carbonado.spi.BaseQueryCompiler; import com.amazon.carbonado.spi.SequenceValueProducer; import com.amazon.carbonado.spi.TriggerManager; import com.amazon.carbonado.util.QuickConstructorGenerator; +import com.amazon.carbonado.qe.AbstractQueryExecutor; +import com.amazon.carbonado.qe.OrderingList; +import com.amazon.carbonado.qe.QueryExecutor; +import com.amazon.carbonado.qe.QueryExecutorFactory; +import com.amazon.carbonado.qe.QueryExecutorCache; +import com.amazon.carbonado.qe.QueryFactory; +import com.amazon.carbonado.qe.StandardQuery; +import com.amazon.carbonado.qe.StandardQueryFactory; + /** * * * @author Brian S O'Neill */ -class JDBCStorage extends BaseQueryCompiler +class JDBCStorage extends StandardQueryFactory implements Storage, JDBCSupport { private static final String TABLE_ALIAS_PREFIX = "T"; @@ -83,13 +92,14 @@ class JDBCStorage extends BaseQueryCompiler final JDBCSupportStrategy mSupportStrategy; final JDBCStorableInfo mInfo; final InstanceFactory mInstanceFactory; + final QueryExecutorFactory mExecutorFactory; final TriggerManager mTriggerManager; JDBCStorage(JDBCRepository repository, JDBCStorableInfo info) throws SupportException { - super(info); + super(info.getStorableType()); mRepository = repository; mSupportStrategy = repository.getSupportStrategy(); mInfo = info; @@ -98,6 +108,8 @@ class JDBCStorage extends BaseQueryCompiler mInstanceFactory = QuickConstructorGenerator .getInstance(generatedStorableClass, InstanceFactory.class); + mExecutorFactory = new QueryExecutorCache(new ExecutorFactory()); + mTriggerManager = new TriggerManager(); } @@ -109,18 +121,6 @@ class JDBCStorage extends BaseQueryCompiler return (S) mInstanceFactory.instantiate(this); } - public Query query() throws FetchException { - return getCompiledQuery(); - } - - public Query query(String filter) throws FetchException { - return getCompiledQuery(filter); - } - - public Query query(Filter filter) throws FetchException { - return getCompiledQuery(filter); - } - public JDBCRepository getJDBCRepository() { return mRepository; } @@ -248,127 +248,137 @@ class JDBCStorage extends BaseQueryCompiler return mInfo; } - protected Query compileQuery(FilterValues values, OrderedProperty[] orderings) - throws FetchException, UnsupportedOperationException - { - JoinNode jn; - try { - JoinNodeBuilder jnb = new JoinNodeBuilder(); - if (values == null) { - jn = new JoinNode(getStorableInfo(), null); - } else { - values.getFilter().accept(jnb, null); - jn = jnb.getRootJoinNode(); - } - jnb.captureOrderings(orderings); - } catch (UndeclaredThrowableException e) { - throw mRepository.toFetchException(e); - } - - StatementBuilder selectBuilder = new StatementBuilder(); - selectBuilder.append("SELECT "); - - // Don't bother using a table alias for one table. With just one table, - // there's no need to disambiguate. - String alias = jn.hasAnyJoins() ? jn.getAlias() : null; + protected StandardQuery createQuery(FilterValues values, OrderingList ordering) { + return new JDBCQuery(values, ordering); + } - Map> properties = getStorableInfo().getAllProperties(); - int ordinal = 0; - for (JDBCStorableProperty property : properties.values()) { - if (!property.isSelectable()) { - continue; - } - if (ordinal > 0) { - selectBuilder.append(','); - } - if (alias != null) { - selectBuilder.append(alias); - selectBuilder.append('.'); - } - selectBuilder.append(property.getColumnName()); - ordinal++; - } + public S instantiate(ResultSet rs) throws SQLException { + return (S) mInstanceFactory.instantiate(this, rs, FIRST_RESULT_INDEX); + } - selectBuilder.append(" FROM"); + public static interface InstanceFactory { + Storable instantiate(JDBCSupport storage); - StatementBuilder fromWhereBuilder = new StatementBuilder(); - fromWhereBuilder.append(" FROM"); + Storable instantiate(JDBCSupport storage, ResultSet rs, int offset) throws SQLException; + } - if (alias == null) { - // Don't bother defining a table alias for one table. - jn.appendTableNameTo(selectBuilder); - jn.appendTableNameTo(fromWhereBuilder); - } else { - jn.appendFullJoinTo(selectBuilder); - jn.appendFullJoinTo(fromWhereBuilder); + private class ExecutorFactory implements QueryExecutorFactory { + public Class getStorableType() { + return JDBCStorage.this.getStorableType(); } - PropertyFilter[] propertyFilters; - boolean[] propertyFilterNullable; - - if (values == null) { - propertyFilters = null; - propertyFilterNullable = null; - } else { - // Build the WHERE clause only if anything to filter on. - selectBuilder.append(" WHERE "); - fromWhereBuilder.append(" WHERE "); - - WhereBuilder wb = new WhereBuilder(selectBuilder, alias == null ? null : jn); - FetchException e = values.getFilter().accept(wb, null); - if (e != null) { - throw e; + public QueryExecutor executor(Filter filter, OrderingList ordering) + throws RepositoryException + { + JoinNode jn; + try { + JoinNodeBuilder jnb = new JoinNodeBuilder(); + if (filter == null) { + jn = new JoinNode(getStorableInfo(), null); + } else { + filter.accept(jnb, null); + jn = jnb.getRootJoinNode(); + } + jnb.captureOrderings(ordering); + } catch (UndeclaredThrowableException e) { + throw mRepository.toFetchException(e); } - propertyFilters = wb.getPropertyFilters(); - propertyFilterNullable = wb.getPropertyFilterNullable(); + StatementBuilder selectBuilder = new StatementBuilder(); + selectBuilder.append("SELECT "); - wb = new WhereBuilder(fromWhereBuilder, alias == null ? null : jn); - e = values.getFilter().accept(wb, null); - if (e != null) { - throw e; - } - } + // Don't bother using a table alias for one table. With just one table, + // there's no need to disambiguate. + String alias = jn.hasAnyJoins() ? jn.getAlias() : null; - // Append order-by clause. - if (orderings != null && orderings.length != 0) { - selectBuilder.append(" ORDER BY "); - ordinal = 0; - for (OrderedProperty orderedProperty : orderings) { + Map> properties = getStorableInfo().getAllProperties(); + int ordinal = 0; + for (JDBCStorableProperty property : properties.values()) { + if (!property.isSelectable()) { + continue; + } if (ordinal > 0) { selectBuilder.append(','); } - selectBuilder.appendColumn(alias == null ? null : jn, - orderedProperty.getChainedProperty()); - if (orderedProperty.getDirection() == Direction.DESCENDING) { - selectBuilder.append(" DESC"); + if (alias != null) { + selectBuilder.append(alias); + selectBuilder.append('.'); } + selectBuilder.append(property.getColumnName()); ordinal++; } - } - try { - CursorFactory factory = new CursorFactory(selectBuilder.build(), - fromWhereBuilder.build(), - propertyFilters, - propertyFilterNullable); - return new JDBCQuery(factory, values, orderings); - } catch (RepositoryException e) { - throw mRepository.toFetchException(e); - } - } + selectBuilder.append(" FROM"); - public S instantiate(ResultSet rs) throws SQLException { - return (S) mInstanceFactory.instantiate(this, rs, FIRST_RESULT_INDEX); - } + StatementBuilder fromWhereBuilder = new StatementBuilder(); + fromWhereBuilder.append(" FROM"); - public static interface InstanceFactory { - Storable instantiate(JDBCSupport storage); + if (alias == null) { + // Don't bother defining a table alias for one table. + jn.appendTableNameTo(selectBuilder); + jn.appendTableNameTo(fromWhereBuilder); + } else { + jn.appendFullJoinTo(selectBuilder); + jn.appendFullJoinTo(fromWhereBuilder); + } - Storable instantiate(JDBCSupport storage, ResultSet rs, int offset) throws SQLException; + PropertyFilter[] propertyFilters; + boolean[] propertyFilterNullable; + + if (filter == null) { + propertyFilters = null; + propertyFilterNullable = null; + } else { + // Build the WHERE clause only if anything to filter on. + selectBuilder.append(" WHERE "); + fromWhereBuilder.append(" WHERE "); + + WhereBuilder wb = new WhereBuilder(selectBuilder, alias == null ? null : jn); + FetchException e = filter.accept(wb, null); + if (e != null) { + throw e; + } + + propertyFilters = wb.getPropertyFilters(); + propertyFilterNullable = wb.getPropertyFilterNullable(); + + wb = new WhereBuilder(fromWhereBuilder, alias == null ? null : jn); + e = filter.accept(wb, null); + if (e != null) { + throw e; + } + } + + // Append order-by clause. + if (ordering != null && ordering.size() != 0) { + selectBuilder.append(" ORDER BY "); + ordinal = 0; + for (OrderedProperty orderedProperty : ordering) { + if (ordinal > 0) { + selectBuilder.append(','); + } + selectBuilder.appendColumn(alias == null ? null : jn, + orderedProperty.getChainedProperty()); + if (orderedProperty.getDirection() == Direction.DESCENDING) { + selectBuilder.append(" DESC"); + } + ordinal++; + } + } + + return new Executor(filter, + ordering, + selectBuilder.build(), + fromWhereBuilder.build(), + propertyFilters, + propertyFilterNullable); + } } - private class CursorFactory { + private class Executor extends AbstractQueryExecutor { + private final Filter mFilter; + private final OrderingList mOrdering; + private final Statement mSelectStatement; private final int mMaxSelectStatementLength; private final Statement mFromWhereStatement; @@ -387,12 +397,17 @@ class JDBCStorage extends BaseQueryCompiler // Some entries may be null if no adapter required. private final Object[] mAdapterInstances; - CursorFactory(Statement selectStatement, - Statement fromWhereStatement, - PropertyFilter[] propertyFilters, - boolean[] propertyFilterNullable) + Executor(Filter filter, + OrderingList ordering, + Statement selectStatement, + Statement fromWhereStatement, + PropertyFilter[] propertyFilters, + boolean[] propertyFilterNullable) throws RepositoryException { + mFilter = filter; + mOrdering = ordering; + mSelectStatement = selectStatement; mMaxSelectStatementLength = selectStatement.maxLength(); mFromWhereStatement = fromWhereStatement; @@ -440,21 +455,69 @@ class JDBCStorage extends BaseQueryCompiler } } - JDBCCursor openCursor(FilterValues filterValues, boolean forUpdate) - throws FetchException - { + public Cursor fetch(FilterValues values) throws FetchException { + boolean forUpdate = mRepository.openTransactionManager().isForUpdate(); Connection con = mRepository.getConnection(); try { - PreparedStatement ps = - con.prepareStatement(prepareSelect(filterValues, forUpdate)); - - setParameters(ps, filterValues); + PreparedStatement ps = con.prepareStatement(prepareSelect(values, forUpdate)); + setParameters(ps, values); return new JDBCCursor(JDBCStorage.this, con, ps); } catch (Exception e) { throw mRepository.toFetchException(e); } } + @Override + public long count(FilterValues values) throws FetchException { + Connection con = mRepository.getConnection(); + try { + PreparedStatement ps = con.prepareStatement(prepareCount(values)); + setParameters(ps, values); + ResultSet rs = ps.executeQuery(); + try { + rs.next(); + return rs.getLong(1); + } finally { + rs.close(); + } + } catch (Exception e) { + throw mRepository.toFetchException(e); + } finally { + mRepository.yieldConnection(con); + } + } + + public Filter getFilter() { + return mFilter; + } + + public OrderingList getOrdering() { + return mOrdering; + } + + public boolean printNative(Appendable app, int indentLevel, FilterValues values) + throws IOException + { + indent(app, indentLevel); + boolean forUpdate = mRepository.openTransactionManager().isForUpdate(); + app.append(prepareSelect(values, forUpdate)); + app.append('\n'); + return true; + } + + public boolean printPlan(Appendable app, int indentLevel, FilterValues values) + throws IOException + { + try { + boolean forUpdate = mRepository.openTransactionManager().isForUpdate(); + String statement = prepareSelect(values, forUpdate); + return mRepository.getSupportStrategy().printPlan(app, indentLevel, statement); + } catch (FetchException e) { + LogFactory.getLog(JDBCStorage.class).error(null, e); + return false; + } + } + /** * Delete operation is included in cursor factory for ease of implementation. */ @@ -480,29 +543,7 @@ class JDBCStorage extends BaseQueryCompiler } } - /** - * Count operation is included in cursor factory for ease of implementation. - */ - long executeCount(FilterValues filterValues) throws FetchException { - Connection con = mRepository.getConnection(); - try { - PreparedStatement ps = con.prepareStatement(prepareCount(filterValues)); - setParameters(ps, filterValues); - ResultSet rs = ps.executeQuery(); - try { - rs.next(); - return rs.getLong(1); - } finally { - rs.close(); - } - } catch (Exception e) { - throw mRepository.toFetchException(e); - } finally { - mRepository.yieldConnection(con); - } - } - - String prepareSelect(FilterValues filterValues, boolean forUpdate) { + private String prepareSelect(FilterValues filterValues, boolean forUpdate) { if (!forUpdate) { return mSelectStatement.buildStatement(mMaxSelectStatementLength, filterValues); } @@ -514,7 +555,7 @@ class JDBCStorage extends BaseQueryCompiler return b.toString(); } - String prepareDelete(FilterValues filterValues) { + private String prepareDelete(FilterValues filterValues) { // Allocate with extra room for "DELETE" StringBuilder b = new StringBuilder(6 + mMaxFromWhereStatementLength); b.append("DELETE"); @@ -522,7 +563,7 @@ class JDBCStorage extends BaseQueryCompiler return b.toString(); } - String prepareCount(FilterValues filterValues) { + private String prepareCount(FilterValues filterValues) { // Allocate with extra room for "SELECT COUNT(*)" StringBuilder b = new StringBuilder(15 + mMaxFromWhereStatementLength); b.append("SELECT COUNT(*)"); @@ -569,77 +610,40 @@ class JDBCStorage extends BaseQueryCompiler } } - private class JDBCQuery extends BaseQuery { - private final CursorFactory mCursorFactory; - - JDBCQuery(CursorFactory factory, - FilterValues values, - OrderedProperty[] orderings) - { - super(mRepository, JDBCStorage.this, values, orderings); - mCursorFactory = factory; - } - - JDBCQuery(CursorFactory factory, - FilterValues values, - String[] orderings) - { - super(mRepository, JDBCStorage.this, values, orderings); - mCursorFactory = factory; - } - - public Query orderBy(String property) - throws FetchException, UnsupportedOperationException - { - return JDBCStorage.this.getOrderedQuery(getFilterValues(), property); - } - - public Query orderBy(String... properties) - throws FetchException, UnsupportedOperationException - { - return JDBCStorage.this.getOrderedQuery(getFilterValues(), properties); - } - - public Cursor fetch() throws FetchException { - boolean forUpdate = mRepository.openTransactionManager().isForUpdate(); - return mCursorFactory.openCursor(getFilterValues(), forUpdate); + private class JDBCQuery extends StandardQuery { + JDBCQuery(FilterValues values, OrderingList ordering) { + super(values, ordering); } + @Override public void deleteAll() throws PersistException { if (mTriggerManager.getDeleteTrigger() != null) { // Super implementation loads one at time and calls // delete. This allows delete trigger to be invoked on each. super.deleteAll(); } else { - mCursorFactory.executeDelete(getFilterValues()); + try { + ((Executor) executor()).executeDelete(getFilterValues()); + } catch (RepositoryException e) { + throw e.toPersistException(); + } } } - public long count() throws FetchException { - return mCursorFactory.executeCount(getFilterValues()); + protected Transaction enterTransaction(IsolationLevel level) { + return getRootRepository().enterTransaction(level); } - public boolean printNative(Appendable app, int indentLevel) throws IOException { - indent(app, indentLevel); - boolean forUpdate = mRepository.openTransactionManager().isForUpdate(); - app.append(mCursorFactory.prepareSelect(getFilterValues(), forUpdate)); - app.append('\n'); - return true; + protected QueryFactory queryFactory() { + return JDBCStorage.this; } - public boolean printPlan(Appendable app, int indentLevel) throws IOException { - try { - boolean forUpdate = mRepository.openTransactionManager().isForUpdate(); - String statement = mCursorFactory.prepareSelect(getFilterValues(), forUpdate); - return mRepository.getSupportStrategy().printPlan(app, indentLevel, statement); - } catch (FetchException e) { - LogFactory.getLog(JDBCStorage.class).error(null, e); - return false; - } + protected QueryExecutorFactory executorFactory() { + return JDBCStorage.this.mExecutorFactory; } - protected BaseQuery newInstance(FilterValues values) { - return new JDBCQuery(mCursorFactory, values, getOrderings()); + protected StandardQuery newInstance(FilterValues values, OrderingList ordering) { + return new JDBCQuery(values, ordering); } } @@ -818,10 +822,10 @@ class JDBCStorage extends BaseQueryCompiler * * @throws UndeclaredThrowableException wraps a RepositoryException */ - public void captureOrderings(OrderedProperty[] orderings) { + public void captureOrderings(OrderingList ordering) { try { - if (orderings != null) { - for (OrderedProperty orderedProperty : orderings) { + if (ordering != null) { + for (OrderedProperty orderedProperty : ordering) { ChainedProperty chained = orderedProperty.getChainedProperty(); mAliasCounter = mRootJoinNode.addJoin(chained, mAliasCounter); } -- cgit v1.2.3