18 package com.mysql.clusterj.core.query;
20 import com.mysql.clusterj.ClusterJUserException;
21 import com.mysql.clusterj.core.metadata.AbstractDomainFieldHandlerImpl;
23 import com.mysql.clusterj.core.query.PredicateImpl.ScanType;
24 import com.mysql.clusterj.core.spi.QueryExecutionContext;
25 import com.mysql.clusterj.core.store.Index;
26 import com.mysql.clusterj.core.store.IndexScanOperation;
27 import com.mysql.clusterj.core.store.Operation;
29 import com.mysql.clusterj.core.util.I18NHelper;
30 import com.mysql.clusterj.core.util.Logger;
31 import com.mysql.clusterj.core.util.LoggerFactoryService;
33 import java.util.ArrayList;
34 import java.util.List;
58 private String className =
"none";
59 private Index storeIndex;
60 private String indexName =
"none";
61 private boolean unique;
62 private boolean multiRange =
false;
63 private CandidateColumnImpl[] candidateColumns = null;
65 private int fieldScore = 1;
69 if (logger.isDebugEnabled()) logger.debug(
"className: " + className
70 +
" storeIndex: " + storeIndex.
getName()
71 +
" unique: " + Boolean.toString(unique)
72 +
" fields: " + toString(fields));
73 this.className = className;
74 this.storeIndex = storeIndex;
75 this.indexName = storeIndex.
getName();
77 this.candidateColumns =
new CandidateColumnImpl[fields.length];
78 if (fields.length == 1) {
80 this.fieldScore = fields[0].getColumnNames().length;
84 CandidateColumnImpl candidateColumn =
new CandidateColumnImpl(domainFieldHandler);
85 candidateColumns[i++] = candidateColumn;
87 if (logger.isDebugEnabled()) logger.debug(toString());
91 StringBuilder builder =
new StringBuilder();
94 builder.append(separator);
95 builder.append(field.getName());
99 return builder.toString();
107 return indexForNullWhereClause;
116 public String toString() {
118 buffer.append(
"CandidateIndexImpl for class: ");
119 buffer.append(className);
120 buffer.append(
" index: ");
121 buffer.append(indexName);
122 buffer.append(
" unique: ");
123 buffer.append(unique);
124 if (candidateColumns != null) {
125 for (CandidateColumnImpl column:candidateColumns) {
126 buffer.append(
" field: ");
127 buffer.append(column.domainFieldHandler.getName());
130 buffer.append(
" no fields.");
132 return buffer.toString();
135 public void markLowerBound(
int fieldNumber, PredicateImpl predicate,
boolean strict) {
136 if (candidateColumns != null) {
137 candidateColumns[fieldNumber].markLowerBound(predicate, strict);
141 public void markUpperBound(
int fieldNumber, PredicateImpl predicate,
boolean strict) {
142 if (candidateColumns != null) {
143 candidateColumns[fieldNumber].markUpperBound(predicate, strict);
147 public void markEqualBound(
int fieldNumber, PredicateImpl predicate) {
148 if (candidateColumns != null) {
149 candidateColumns[fieldNumber].markEqualBound(predicate);
153 public void markInBound(
int fieldNumber, InPredicateImpl predicate) {
154 if (candidateColumns != null) {
155 candidateColumns[fieldNumber].markInBound(predicate);
163 CandidateColumnImpl lastLowerBoundColumn = null;
164 CandidateColumnImpl lastUpperBoundColumn = null;
179 synchronized int getScore() {
180 if (candidateColumns == null) {
184 boolean lowerBoundDone =
false;
185 boolean upperBoundDone =
false;
188 for (CandidateColumnImpl column: candidateColumns) {
189 if (!(column.equalBound)) {
194 if (
"PRIMARY".equals(indexName)) {
195 scanType = PredicateImpl.ScanType.PRIMARY_KEY;
197 scanType = PredicateImpl.ScanType.UNIQUE_KEY;
204 for (CandidateColumnImpl candidateColumn: candidateColumns) {
205 if ((candidateColumn.equalBound)) {
206 scanType = PredicateImpl.ScanType.INDEX_SCAN;
207 if (!lowerBoundDone) {
208 result += fieldScore;
209 lastLowerBoundColumn = candidateColumn;
211 if (!upperBoundDone) {
212 result += fieldScore;
213 lastUpperBoundColumn = candidateColumn;
215 }
else if ((candidateColumn.inBound)) {
216 scanType = PredicateImpl.ScanType.INDEX_SCAN;
218 if (!lowerBoundDone) {
219 result += fieldScore;
220 lastLowerBoundColumn = candidateColumn;
222 if (!upperBoundDone) {
223 result += fieldScore;
224 lastUpperBoundColumn = candidateColumn;
226 }
else if (!(lowerBoundDone && upperBoundDone)) {
228 boolean hasLowerBound = candidateColumn.hasLowerBound();
229 boolean hasUpperBound = candidateColumn.hasUpperBound();
231 if (hasLowerBound || hasUpperBound) {
232 scanType = PredicateImpl.ScanType.INDEX_SCAN;
234 if (!lowerBoundDone) {
236 result += fieldScore;
237 lastLowerBoundColumn = candidateColumn;
239 lowerBoundDone =
true;
242 if (!upperBoundDone) {
244 result += fieldScore;
245 lastUpperBoundColumn = candidateColumn;
247 upperBoundDone =
true;
250 if (lowerBoundDone && upperBoundDone) {
255 if (lastLowerBoundColumn != null) {
256 lastLowerBoundColumn.markLastLowerBoundColumn();
258 if (lastUpperBoundColumn != null) {
259 lastUpperBoundColumn.markLastUpperBoundColumn();
265 public ScanType getScanType() {
270 private final int BOUND_STATUS_NO_BOUND_DONE = 0;
272 private final int BOUND_STATUS_LOWER_BOUND_DONE = 1;
274 private final int BOUND_STATUS_UPPER_BOUND_DONE = 2;
276 private final int BOUND_STATUS_BOTH_BOUNDS_DONE = 3;
290 void operationSetBounds(QueryExecutionContext context, IndexScanOperation op) {
294 for (CandidateColumnImpl candidateColumn:candidateColumns) {
295 if (candidateColumn.hasInBound()) {
296 parameterSizes.add(candidateColumn.getParameterSize(context));
299 if (parameterSizes.size() > 1) {
300 throw new ClusterJUserException(local.
message(
"ERR_Too_Many_In_For_Index", indexName));
303 if (candidateColumns.length == 1) {
304 candidateColumns[0].operationSetAllBounds(context, op);
307 for (
int parameterIndex = 0; parameterIndex < parameterSizes.get(0); ++parameterIndex) {
308 int boundStatus = BOUND_STATUS_NO_BOUND_DONE;
309 for (CandidateColumnImpl candidateColumn:candidateColumns) {
310 if (logger.isDetailEnabled()) logger.detail(
311 "parameterIndex: " + parameterIndex
312 +
" boundStatus: " + boundStatus
313 +
" candidateColumn: " + candidateColumn.domainFieldHandler.getName());
315 if (boundStatus != BOUND_STATUS_BOTH_BOUNDS_DONE) {
316 boundStatus = candidateColumn.operationSetBounds(context, op, parameterIndex, boundStatus);
320 op.endBound(parameterIndex);
325 int boundStatus = BOUND_STATUS_NO_BOUND_DONE;
326 for (CandidateColumnImpl candidateColumn:candidateColumns) {
327 if (logger.isDetailEnabled()) logger.detail(
"boundStatus: " + boundStatus
328 +
" candidateColumn: " + candidateColumn.domainFieldHandler.getName());
330 if (boundStatus != BOUND_STATUS_BOTH_BOUNDS_DONE) {
331 boundStatus = candidateColumn.operationSetBounds(context, op, -1, boundStatus);
337 void operationSetKeys(QueryExecutionContext context,
339 for (CandidateColumnImpl candidateColumn:candidateColumns) {
341 candidateColumn.operationSetKeys(context, op);
350 class CandidateColumnImpl {
352 protected AbstractDomainFieldHandlerImpl domainFieldHandler;
353 protected PredicateImpl lowerBoundPredicate;
354 protected PredicateImpl upperBoundPredicate;
355 protected PredicateImpl equalPredicate;
356 protected InPredicateImpl inPredicate;
357 protected Boolean lowerBoundStrict = null;
358 protected Boolean upperBoundStrict = null;
359 protected boolean equalBound =
false;
360 protected boolean inBound =
false;
361 protected boolean lastLowerBoundColumn =
false;
362 protected boolean lastUpperBoundColumn =
false;
364 protected boolean hasLowerBound() {
365 return lowerBoundPredicate != null || equalPredicate != null || inPredicate != null;
373 public void operationSetAllBounds(QueryExecutionContext context, IndexScanOperation op) {
374 inPredicate.operationSetAllBounds(context, op);
377 public int getParameterSize(QueryExecutionContext context) {
379 return inPredicate.getParameterSize(context);
382 protected boolean hasUpperBound() {
383 return upperBoundPredicate != null || equalPredicate != null || inPredicate != null;
386 protected boolean hasInBound() {
390 private CandidateColumnImpl(AbstractDomainFieldHandlerImpl domainFieldHandler) {
391 this.domainFieldHandler = domainFieldHandler;
394 private void markLastLowerBoundColumn() {
395 lastLowerBoundColumn =
true;
398 private void markLastUpperBoundColumn() {
399 lastUpperBoundColumn =
true;
402 private void markLowerBound(PredicateImpl predicate,
boolean strict) {
403 lowerBoundStrict = strict;
404 this.lowerBoundPredicate = predicate;
407 private void markUpperBound(PredicateImpl predicate,
boolean strict) {
408 upperBoundStrict = strict;
409 this.upperBoundPredicate = predicate;
412 private void markEqualBound(PredicateImpl predicate) {
414 this.equalPredicate = predicate;
417 public void markInBound(InPredicateImpl predicate) {
419 this.inPredicate = predicate;
428 private int operationSetBounds(
429 QueryExecutionContext context, IndexScanOperation op,
int index,
int boundStatus) {
431 if (logger.isDetailEnabled()) logger.detail(
"column: " + domainFieldHandler.getName()
432 +
" boundStatus: " + boundStatus
433 +
" lastLowerBoundColumn: " + lastLowerBoundColumn
434 +
" lastUpperBoundColumn: " + lastUpperBoundColumn);
435 switch(boundStatus) {
436 case BOUND_STATUS_BOTH_BOUNDS_DONE:
438 return BOUND_STATUS_BOTH_BOUNDS_DONE;
439 case BOUND_STATUS_NO_BOUND_DONE:
441 if (equalPredicate != null) {
442 equalPredicate.operationSetBounds(context, op,
true);
444 if (inPredicate != null) {
445 inPredicate.operationSetBound(context, op, index,
true);
447 if (lowerBoundPredicate != null) {
448 lowerBoundPredicate.operationSetLowerBound(context, op, lastLowerBoundColumn);
450 if (upperBoundPredicate != null) {
451 upperBoundPredicate.operationSetUpperBound(context, op, lastUpperBoundColumn);
454 case BOUND_STATUS_LOWER_BOUND_DONE:
456 if (equalPredicate != null) {
457 equalPredicate.operationSetUpperBound(context, op, lastUpperBoundColumn);
459 if (inPredicate != null) {
460 inPredicate.operationSetUpperBound(context, op, index);
462 if (upperBoundPredicate != null) {
463 upperBoundPredicate.operationSetUpperBound(context, op, lastUpperBoundColumn);
466 case BOUND_STATUS_UPPER_BOUND_DONE:
468 if (equalPredicate != null) {
469 equalPredicate.operationSetLowerBound(context, op, lastLowerBoundColumn);
471 if (inPredicate != null) {
472 inPredicate.operationSetLowerBound(context, op, index);
474 if (lowerBoundPredicate != null) {
475 lowerBoundPredicate.operationSetLowerBound(context, op, lastLowerBoundColumn);
479 if (!hasLowerBound()) {
481 boundStatus |= BOUND_STATUS_LOWER_BOUND_DONE;
483 if (!hasUpperBound()) {
485 boundStatus |= BOUND_STATUS_UPPER_BOUND_DONE;
490 private void operationSetKeys(QueryExecutionContext context, Operation op) {
491 equalPredicate.operationEqual(context, op);
504 return numberOfConditions == candidateColumns.length;
510 public Index getStoreIndex() {
514 public boolean isMultiRange() {