From b845f7f86bfb7150924d968335535ce26c592b82 Mon Sep 17 00:00:00 2001
From: "Brian S. O'Neill" <bronee@gmail.com>
Date: Mon, 11 Sep 2006 04:48:34 +0000
Subject: Switch JDBC repository to use new query engine.

---
 .../amazon/carbonado/qe/QueryExecutorCache.java    |   2 +-
 .../com/amazon/carbonado/qe/StandardQuery.java     |  31 +-
 .../amazon/carbonado/qe/StandardQueryFactory.java  |  23 +-
 .../amazon/carbonado/repo/jdbc/JDBCStorage.java    | 420 +++++++++++----------
 4 files changed, 242 insertions(+), 234 deletions(-)

(limited to 'src/main')

diff --git a/src/main/java/com/amazon/carbonado/qe/QueryExecutorCache.java b/src/main/java/com/amazon/carbonado/qe/QueryExecutorCache.java
index da944fa..2729851 100644
--- a/src/main/java/com/amazon/carbonado/qe/QueryExecutorCache.java
+++ b/src/main/java/com/amazon/carbonado/qe/QueryExecutorCache.java
@@ -42,7 +42,7 @@ public class QueryExecutorCache<S extends Storable> implements QueryExecutorFact
     // Maps filters to maps which map ordering lists to executors.
     private final Map<Filter<S>, Map<OrderingList<S>, QueryExecutor<S>>> mFilterToExecutor;
 
-    protected QueryExecutorCache(QueryExecutorFactory<S> factory) {
+    public QueryExecutorCache(QueryExecutorFactory<S> factory) {
         if (factory == null) {
             throw new IllegalArgumentException();
         }
diff --git a/src/main/java/com/amazon/carbonado/qe/StandardQuery.java b/src/main/java/com/amazon/carbonado/qe/StandardQuery.java
index bb1dcc3..2e1cdfc 100644
--- a/src/main/java/com/amazon/carbonado/qe/StandardQuery.java
+++ b/src/main/java/com/amazon/carbonado/qe/StandardQuery.java
@@ -363,11 +363,23 @@ public abstract class StandardQuery<S extends Storable> extends AbstractQuery<S>
         return values;
     }
 
+    /**
+     * Returns the executor in use by this query.
+     */
+    protected QueryExecutor<S> executor() throws RepositoryException {
+        QueryExecutor<S> executor = mExecutor;
+        if (executor == null) {
+            Filter<S> filter = mValues == null ? null : mValues.getFilter();
+            mExecutor = executor = executorFactory().executor(filter, mOrdering);
+        }
+        return executor;
+    }
+
     /**
      * Ensures that a cached query executor reference is available. If not, the
      * query executor factory is called and the executor is cached.
      */
-    protected void setExecutorReference() throws RepositoryException {
+    protected void setExecutor() throws RepositoryException {
         executor();
     }
 
@@ -375,7 +387,7 @@ public abstract class StandardQuery<S extends Storable> extends AbstractQuery<S>
      * Resets any cached reference to a query executor. If a reference is
      * available, it is replaced, but a clear reference is not set.
      */
-    protected void resetExecutorReference() throws RepositoryException {
+    protected void resetExecutor() throws RepositoryException {
         if (mExecutor != null) {
             Filter<S> filter = mValues == null ? null : mValues.getFilter();
             mExecutor = executorFactory().executor(filter, mOrdering);
@@ -387,7 +399,7 @@ public abstract class StandardQuery<S extends Storable> extends AbstractQuery<S>
      * Query is used, it will get an executor from the query executor factory
      * and cache a reference to it.
      */
-    protected void clearExecutorReference() {
+    protected void clearExecutor() {
         mExecutor = null;
     }
 
@@ -415,10 +427,10 @@ public abstract class StandardQuery<S extends Storable> extends AbstractQuery<S>
      * passed in the constructor.
      *
      * @param values optional values object, defaults to open filter if null
-     * @param orderings order-by properties, never null
+     * @param ordering order-by properties, never null
      */
     protected abstract StandardQuery<S> newInstance(FilterValues<S> values,
-                                                    OrderingList<S> orderings);
+                                                    OrderingList<S> ordering);
 
     private StandardQuery<S> newInstance(FilterValues<S> values) {
         return newInstance(values, mOrdering);
@@ -433,13 +445,4 @@ public abstract class StandardQuery<S extends Storable> extends AbstractQuery<S>
     {
         return queryFactory().query(values, ordering);
     }
-
-    private QueryExecutor<S> executor() throws RepositoryException {
-        QueryExecutor<S> executor = mExecutor;
-        if (executor == null) {
-            Filter<S> filter = mValues == null ? null : mValues.getFilter();
-            mExecutor = executor = executorFactory().executor(filter, mOrdering);
-        }
-        return executor;
-    }
 }
diff --git a/src/main/java/com/amazon/carbonado/qe/StandardQueryFactory.java b/src/main/java/com/amazon/carbonado/qe/StandardQueryFactory.java
index 8b9a3a9..c9b0557 100644
--- a/src/main/java/com/amazon/carbonado/qe/StandardQueryFactory.java
+++ b/src/main/java/com/amazon/carbonado/qe/StandardQueryFactory.java
@@ -135,7 +135,7 @@ public abstract class StandardQueryFactory<S extends Storable> implements QueryF
                     StandardQuery<S> standardQuery = createQuery(values, ordering);
                     if (!mLazySetExecutor) {
                         try {
-                            standardQuery.setExecutorReference();
+                            standardQuery.setExecutor();
                         } catch (RepositoryException e) {
                             throw e.toFetchException();
                         }
@@ -168,33 +168,33 @@ public abstract class StandardQueryFactory<S extends Storable> implements QueryF
     }
 
     /**
-     * For each cached query, calls {@link StandardQuery#setExecutorReference}.
+     * For each cached query, calls {@link StandardQuery#setExecutor}.
      */
-    public void setExecutorReferences() throws RepositoryException {
+    public void setExecutors() throws RepositoryException {
         for (StandardQuery<S> query : gatherQueries()) {
-            query.setExecutorReference();
+            query.setExecutor();
         }
     }
 
     /**
-     * For each cached query, calls {@link StandardQuery#resetExecutorReference}.
+     * For each cached query, calls {@link StandardQuery#resetExecutor}.
      * This call can be used to rebuild all cached query plans after the set of
      * available indexes has changed.
      */
-    public void resetExecutorReferences() throws RepositoryException {
+    public void resetExecutors() throws RepositoryException {
         for (StandardQuery<S> query : gatherQueries()) {
-            query.resetExecutorReference();
+            query.resetExecutor();
         }
     }
 
     /**
-     * For each cached query, calls {@link StandardQuery#clearExecutorReference}.
+     * For each cached query, calls {@link StandardQuery#clearExecutor}.
      * This call can be used to clear all cached query plans after the set of
      * available indexes has changed.
      */
-    public void clearExecutorReferences() {
+    public void clearExecutos() {
         for (StandardQuery<S> query : gatherQueries()) {
-            query.clearExecutorReference();
+            query.clearExecutor();
         }
     }
 
@@ -205,7 +205,8 @@ public abstract class StandardQueryFactory<S extends Storable> implements QueryF
      * @param ordering optional order-by properties
      */
     protected abstract StandardQuery<S> createQuery(FilterValues<S> values,
-                                                    OrderingList<S> ordering);
+                                                    OrderingList<S> ordering)
+        throws FetchException;
 
     private ArrayList<StandardQuery<S>> gatherQueries() {
         // Copy all queries and operate on the copy instead of holding lock for
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<S extends Storable> extends BaseQueryCompiler<S>
+class JDBCStorage<S extends Storable> extends StandardQueryFactory<S>
     implements Storage<S>, JDBCSupport<S>
 {
     private static final String TABLE_ALIAS_PREFIX = "T";
@@ -83,13 +92,14 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
     final JDBCSupportStrategy mSupportStrategy;
     final JDBCStorableInfo<S> mInfo;
     final InstanceFactory mInstanceFactory;
+    final QueryExecutorFactory<S> mExecutorFactory;
 
     final TriggerManager<S> mTriggerManager;
 
     JDBCStorage(JDBCRepository repository, JDBCStorableInfo<S> info)
         throws SupportException
     {
-        super(info);
+        super(info.getStorableType());
         mRepository = repository;
         mSupportStrategy = repository.getSupportStrategy();
         mInfo = info;
@@ -98,6 +108,8 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
         mInstanceFactory = QuickConstructorGenerator
             .getInstance(generatedStorableClass, InstanceFactory.class);
 
+        mExecutorFactory = new QueryExecutorCache<S>(new ExecutorFactory());
+
         mTriggerManager = new TriggerManager<S>();
     }
 
@@ -109,18 +121,6 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
         return (S) mInstanceFactory.instantiate(this);
     }
 
-    public Query<S> query() throws FetchException {
-        return getCompiledQuery();
-    }
-
-    public Query<S> query(String filter) throws FetchException {
-        return getCompiledQuery(filter);
-    }
-
-    public Query<S> query(Filter<S> filter) throws FetchException {
-        return getCompiledQuery(filter);
-    }
-
     public JDBCRepository getJDBCRepository() {
         return mRepository;
     }
@@ -248,127 +248,137 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
         return mInfo;
     }
 
-    protected Query<S> compileQuery(FilterValues<S> values, OrderedProperty<S>[] 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<S> createQuery(FilterValues<S> values, OrderingList<S> ordering) {
+        return new JDBCQuery(values, ordering);
+    }
 
-        Map<String, JDBCStorableProperty<S>> properties = getStorableInfo().getAllProperties();
-        int ordinal = 0;
-        for (JDBCStorableProperty<S> 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<S> {
+        public Class<S> getStorableType() {
+            return JDBCStorage.this.getStorableType();
         }
 
-        PropertyFilter<S>[] 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<S> executor(Filter<S> filter, OrderingList<S> 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<S> orderedProperty : orderings) {
+            Map<String, JDBCStorableProperty<S>> properties = getStorableInfo().getAllProperties();
+            int ordinal = 0;
+            for (JDBCStorableProperty<S> 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<S>[] 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<S> 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<S> {
+        private final Filter<S> mFilter;
+        private final OrderingList<S> mOrdering;
+
         private final Statement<S> mSelectStatement;
         private final int mMaxSelectStatementLength;
         private final Statement<S> mFromWhereStatement;
@@ -387,12 +397,17 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
         // Some entries may be null if no adapter required.
         private final Object[] mAdapterInstances;
 
-        CursorFactory(Statement<S> selectStatement,
-                      Statement<S> fromWhereStatement,
-                      PropertyFilter<S>[] propertyFilters,
-                      boolean[] propertyFilterNullable)
+        Executor(Filter<S> filter,
+                 OrderingList<S> ordering,
+                 Statement<S> selectStatement,
+                 Statement<S> fromWhereStatement,
+                 PropertyFilter<S>[] propertyFilters,
+                 boolean[] propertyFilterNullable)
             throws RepositoryException
         {
+            mFilter = filter;
+            mOrdering = ordering;
+
             mSelectStatement = selectStatement;
             mMaxSelectStatementLength = selectStatement.maxLength();
             mFromWhereStatement = fromWhereStatement;
@@ -440,21 +455,69 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
             }
         }
 
-        JDBCCursor<S> openCursor(FilterValues<S> filterValues, boolean forUpdate)
-            throws FetchException
-        {
+        public Cursor<S> fetch(FilterValues<S> 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<S>(JDBCStorage.this, con, ps);
             } catch (Exception e) {
                 throw mRepository.toFetchException(e);
             }
         }
 
+        @Override
+        public long count(FilterValues<S> 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<S> getFilter() {
+            return mFilter;
+        }
+
+        public OrderingList<S> getOrdering() {
+            return mOrdering;
+        }
+
+        public boolean printNative(Appendable app, int indentLevel, FilterValues<S> 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<S> 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<S extends Storable> extends BaseQueryCompiler<S>
             }
         }
 
-        /**
-         * Count operation is included in cursor factory for ease of implementation.
-         */
-        long executeCount(FilterValues<S> 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<S> filterValues, boolean forUpdate) {
+        private String prepareSelect(FilterValues<S> filterValues, boolean forUpdate) {
             if (!forUpdate) {
                 return mSelectStatement.buildStatement(mMaxSelectStatementLength, filterValues);
             }
@@ -514,7 +555,7 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
             return b.toString();
         }
 
-        String prepareDelete(FilterValues<S> filterValues) {
+        private String prepareDelete(FilterValues<S> filterValues) {
             // Allocate with extra room for "DELETE"
             StringBuilder b = new StringBuilder(6 + mMaxFromWhereStatementLength);
             b.append("DELETE");
@@ -522,7 +563,7 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
             return b.toString();
         }
 
-        String prepareCount(FilterValues<S> filterValues) {
+        private String prepareCount(FilterValues<S> filterValues) {
             // Allocate with extra room for "SELECT COUNT(*)"
             StringBuilder b = new StringBuilder(15 + mMaxFromWhereStatementLength);
             b.append("SELECT COUNT(*)");
@@ -569,77 +610,40 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
         }
     }
 
-    private class JDBCQuery extends BaseQuery<S> {
-        private final CursorFactory mCursorFactory;
-
-        JDBCQuery(CursorFactory factory,
-                  FilterValues<S> values,
-                  OrderedProperty<S>[] orderings)
-        {
-            super(mRepository, JDBCStorage.this, values, orderings);
-            mCursorFactory = factory;
-        }
-
-        JDBCQuery(CursorFactory factory,
-                  FilterValues<S> values,
-                  String[] orderings)
-        {
-            super(mRepository, JDBCStorage.this, values, orderings);
-            mCursorFactory = factory;
-        }
-
-        public Query<S> orderBy(String property)
-            throws FetchException, UnsupportedOperationException
-        {
-            return JDBCStorage.this.getOrderedQuery(getFilterValues(), property);
-        }
-
-        public Query<S> orderBy(String... properties)
-            throws FetchException, UnsupportedOperationException
-        {
-            return JDBCStorage.this.getOrderedQuery(getFilterValues(), properties);
-        }
-
-        public Cursor<S> fetch() throws FetchException {
-            boolean forUpdate = mRepository.openTransactionManager().isForUpdate();
-            return mCursorFactory.openCursor(getFilterValues(), forUpdate);
+    private class JDBCQuery extends StandardQuery<S> {
+        JDBCQuery(FilterValues<S> values, OrderingList<S> 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<S> 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<S> executorFactory() {
+            return JDBCStorage.this.mExecutorFactory;
         }
 
-        protected BaseQuery<S> newInstance(FilterValues<S> values) {
-            return new JDBCQuery(mCursorFactory, values, getOrderings());
+        protected StandardQuery<S> newInstance(FilterValues<S> values, OrderingList<S> ordering) {
+            return new JDBCQuery(values, ordering);
         }
     }
 
@@ -818,10 +822,10 @@ class JDBCStorage<S extends Storable> extends BaseQueryCompiler<S>
          *
          * @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