2 Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 package com.mysql.clusterj.core.query;
21 import com.mysql.clusterj.ClusterJException;
22 import com.mysql.clusterj.ClusterJFatalInternalException;
23 import com.mysql.clusterj.ClusterJUserException;
25 import com.mysql.clusterj.core.spi.QueryExecutionContext;
26 import com.mysql.clusterj.core.store.IndexScanOperation;
27 import com.mysql.clusterj.core.store.Operation;
28 import com.mysql.clusterj.core.store.ScanFilter;
29 import com.mysql.clusterj.core.store.ScanOperation;
31 import com.mysql.clusterj.core.util.I18NHelper;
32 import com.mysql.clusterj.core.util.Logger;
33 import com.mysql.clusterj.core.util.LoggerFactoryService;
35 import com.mysql.clusterj.query.Predicate;
37 public abstract class PredicateImpl implements Predicate {
39 /** My message translator */
40 static final I18NHelper local = I18NHelper.getInstance(PredicateImpl.class);
43 static final Logger logger = LoggerFactoryService.getFactory().getInstance(PredicateImpl.class);
45 /** My domain object. */
46 protected QueryDomainTypeImpl<?> dobj;
49 protected enum ScanType {
56 public PredicateImpl(QueryDomainTypeImpl<?> dobj) {
60 public Predicate or(Predicate other) {
61 assertPredicateImpl(other);
62 PredicateImpl otherPredicateImpl = (PredicateImpl)other;
63 assertIdenticalDomainObject(otherPredicateImpl, "or");
64 return new OrPredicateImpl(this.dobj, this, otherPredicateImpl);
67 public Predicate and(Predicate other) {
68 assertPredicateImpl(other);
69 PredicateImpl predicateImpl = (PredicateImpl)other;
70 assertIdenticalDomainObject(predicateImpl, "and");
71 if (other instanceof AndPredicateImpl) {
72 AndPredicateImpl andPredicateImpl = (AndPredicateImpl)other;
73 return andPredicateImpl.and(this);
75 return new AndPredicateImpl(dobj, this, predicateImpl);
79 public Predicate not() {
80 return new NotPredicateImpl(this);
83 void markBoundsForCandidateIndices(QueryExecutionContext context, CandidateIndexImpl[] candidateIndices) {
84 throw new ClusterJFatalInternalException(
85 local.message("ERR_Implementation_Should_Not_Occur"));
88 public void operationSetBounds(QueryExecutionContext context,
89 IndexScanOperation op, boolean lastColumn) {
90 throw new ClusterJFatalInternalException(
91 local.message("ERR_Implementation_Should_Not_Occur"));
94 public void operationSetLowerBound(QueryExecutionContext context,
95 IndexScanOperation op, boolean lastColumn) {
96 throw new ClusterJFatalInternalException(
97 local.message("ERR_Implementation_Should_Not_Occur"));
100 public void operationSetUpperBound(QueryExecutionContext context,
101 IndexScanOperation op, boolean lastColumn){
102 throw new ClusterJFatalInternalException(
103 local.message("ERR_Implementation_Should_Not_Occur"));
106 public void operationEqual(QueryExecutionContext context,
108 throw new ClusterJFatalInternalException(
109 local.message("ERR_Implementation_Should_Not_Occur"));
112 public void operationEqualFor(QueryExecutionContext context,
113 Operation op, String indexName) {
114 throw new ClusterJFatalInternalException(
115 local.message("ERR_Implementation_Should_Not_Occur"));
118 public void objectSetValuesFor(QueryExecutionContext context,
119 Object row, String indexName) {
120 throw new ClusterJFatalInternalException(
121 local.message("ERR_Implementation_Should_Not_Occur"));
124 /** Create a filter for the operation. Set the condition into the
126 * @param context the query execution context with the parameter values
127 * @param op the operation
129 public void filterCmpValue(QueryExecutionContext context,
132 ScanFilter filter = op.getScanFilter(context);
134 filterCmpValue(context, op, filter);
136 } catch (ClusterJException ex) {
138 } catch (Exception ex) {
139 throw new ClusterJException(
140 local.message("ERR_Get_NdbFilter"), ex);
144 public void filterCmpValue(QueryExecutionContext context,
145 ScanOperation op, ScanFilter filter) {
146 throw new ClusterJFatalInternalException(
147 local.message("ERR_Implementation_Should_Not_Occur"));
150 public void assertIdenticalDomainObject(PredicateImpl other, String venue) {
151 QueryDomainTypeImpl<?> otherDomainObject = other.getDomainObject();
152 if (dobj != otherDomainObject) {
153 throw new ClusterJUserException(
154 local.message("ERR_Wrong_Domain_Object", venue));
158 /** Mark this predicate as being satisfied. */
159 void setSatisfied() {
160 throw new UnsupportedOperationException("Not yet implemented");
163 /** Mark all parameters as being required. */
164 public abstract void markParameters();
166 /** Unmark all parameters as being required. */
167 public abstract void unmarkParameters();
169 private void assertPredicateImpl(Predicate other) {
170 if (!(other instanceof PredicateImpl)) {
171 throw new UnsupportedOperationException(
172 local.message("ERR_NotImplemented"));
176 private QueryDomainTypeImpl<?> getDomainObject() {
180 public CandidateIndexImpl getBestCandidateIndex(QueryExecutionContext context) {
181 return getBestCandidateIndexFor(context, this);
184 /** Get the best candidate index for the query, considering all indices
185 * defined and all predicates in the query.
186 * @param predicates the predicates
187 * @return the best index for the query
189 protected CandidateIndexImpl getBestCandidateIndexFor(QueryExecutionContext context,
190 PredicateImpl... predicates) {
191 // Create CandidateIndexImpl to decide how to scan.
192 CandidateIndexImpl[] candidateIndices = dobj.createCandidateIndexes();
193 // Iterate over predicates and have each one register with
194 // candidate indexes.
195 for (PredicateImpl predicateImpl : predicates) {
196 predicateImpl.markBoundsForCandidateIndices(context, candidateIndices);
198 // Iterate over candidate indices to find one that is usable.
200 // Holder for the best index; default to the index for null where clause
201 CandidateIndexImpl bestCandidateIndexImpl =
202 CandidateIndexImpl.getIndexForNullWhereClause();
203 // Hash index operations require the predicates to have no extra conditions
204 // beyond the index columns.
205 int numberOfConditions = getNumberOfConditionsInPredicate();
206 for (CandidateIndexImpl candidateIndex : candidateIndices) {
207 if (candidateIndex.supportsConditionsOfLength(numberOfConditions)) {
208 // opportunity for a user-defined plugin to evaluate indices
209 int score = candidateIndex.getScore();
210 if (logger.isDetailEnabled()) {
211 logger.detail("Score: " + score + " from " + candidateIndex);
213 if (score > highScore) {
214 bestCandidateIndexImpl = candidateIndex;
219 if (logger.isDetailEnabled()) logger.detail("High score: " + highScore
220 + " from " + bestCandidateIndexImpl.getIndexName());
221 return bestCandidateIndexImpl;
224 /** Get the number of conditions in the top level predicate.
225 * This is used to determine whether a hash index can be used. If there
226 * are exactly the number of conditions as index columns, then the
227 * hash index might be used.
228 * By default (for equal, greaterThan, lessThan, greaterEqual, lessEqual)
229 * there is one condition.
230 * AndPredicateImpl overrides this method.
231 * @return the number of conditions
233 protected int getNumberOfConditionsInPredicate() {