You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ds...@apache.org on 2015/07/09 19:02:57 UTC
[39/57] [partial] incubator-geode git commit: Initial import of
geode-1.0.0.0-SNAPSHOT-2. All the new sub-project directories (like jvsd)
were not imported. A diff was done to confirm that this commit is exactly the
same as the open directory the snapsho
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledGroupBySelect.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledGroupBySelect.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledGroupBySelect.java
new file mode 100644
index 0000000..ad41c30
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledGroupBySelect.java
@@ -0,0 +1,506 @@
+package com.gemstone.gemfire.cache.query.internal;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.gemstone.gemfire.cache.query.Aggregator;
+import com.gemstone.gemfire.cache.query.AmbiguousNameException;
+import com.gemstone.gemfire.cache.query.FunctionDomainException;
+import com.gemstone.gemfire.cache.query.NameResolutionException;
+import com.gemstone.gemfire.cache.query.QueryInvalidException;
+import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
+import com.gemstone.gemfire.cache.query.SelectResults;
+import com.gemstone.gemfire.cache.query.Struct;
+import com.gemstone.gemfire.cache.query.TypeMismatchException;
+import com.gemstone.gemfire.cache.query.internal.parse.OQLLexerTokenTypes;
+import com.gemstone.gemfire.cache.query.internal.types.StructTypeImpl;
+import com.gemstone.gemfire.cache.query.internal.types.TypeUtils;
+import com.gemstone.gemfire.cache.query.internal.utils.PDXUtils;
+import com.gemstone.gemfire.cache.query.types.ObjectType;
+import com.gemstone.gemfire.cache.query.types.StructType;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+
+/**
+ *
+ * @author ashahid
+ *
+ */
+public class CompiledGroupBySelect extends CompiledSelect {
+
+ private final BitSet aggregateColsPos;
+ private final CompiledAggregateFunction[] aggregateFunctions;
+ private final boolean isDistinct;
+ private final List<CompiledSortCriterion> originalOrderByClause;
+ private final CompiledValue limit;
+ @Override
+ public int getType() {
+ return GROUP_BY_SELECT;
+ }
+
+ public CompiledGroupBySelect(boolean distinct, boolean count,
+ CompiledValue whereClause, List iterators, List projAttrs,
+ List<CompiledSortCriterion> orderByAttrs, CompiledValue limit,
+ List<String> hints, List<CompiledValue> groupByClause,
+ LinkedHashMap<Integer, CompiledAggregateFunction> aggMap) {
+ super(false, false, whereClause, iterators, projAttrs, null,null,
+ hints, groupByClause);
+ this.aggregateFunctions = new CompiledAggregateFunction[aggMap != null ? aggMap
+ .size() : 0];
+ this.aggregateColsPos = new BitSet(this.projAttrs.size());
+ if (aggMap != null) {
+ int i = 0;
+ for (Map.Entry<Integer, CompiledAggregateFunction> entry : aggMap
+ .entrySet()) {
+ this.aggregateColsPos.set(entry.getKey().intValue());
+ this.aggregateFunctions[i++] = entry.getValue();
+ }
+ }
+ this.originalOrderByClause = orderByAttrs;
+ this.isDistinct = distinct;
+ this.limit = limit;
+ }
+
+ @Override
+ public Set computeDependencies(ExecutionContext context)
+ throws TypeMismatchException, AmbiguousNameException,
+ NameResolutionException {
+ if (!this.transformationDone) {
+ replaceAggregateFunctionInProjection();
+ }
+ return super.computeDependencies(context);
+
+ }
+
+ private void replaceAggregateFunctionInProjection() {
+ // Extract the parameter compiledValues out of aggregate functions &
+ // modify the projection
+ // attributes to have that instead. Empty out the groupByList
+ // Create orderby attribute out of group by
+
+ int bitStart = 0;
+ for (CompiledAggregateFunction aggFunc : this.aggregateFunctions) {
+ int index = this.aggregateColsPos.nextSetBit(bitStart);
+ bitStart = index + 1;
+ CompiledValue param = aggFunc.getParameter();
+ if (param == null
+ && aggFunc.getFunctionType() == OQLLexerTokenTypes.COUNT) {
+ // * case of *, substitue a dummy parameter of compiled literal = 0 to
+ // satisfy the code
+ param = new CompiledLiteral(Integer.valueOf(0));
+
+ } else if (param == null) {
+ throw new QueryInvalidException(
+ "aggregate function passed invalid parameter");
+ }
+ Object[] projAtt = (Object[]) this.projAttrs.get(index);
+ projAtt[1] = param;
+ }
+ }
+
+ private void revertAggregateFunctionInProjection() {
+ // Extract the parameter compiledValues out of aggregate functions &
+ // modify the projection
+ // attributes to have that instead. Empty out the groupByList
+ // Create orderby attribute out of group by
+
+ int bitStart = 0;
+ for (CompiledAggregateFunction aggFunc : this.aggregateFunctions) {
+ int index = this.aggregateColsPos.nextSetBit(bitStart);
+ bitStart = index + 1;
+ Object[] projAtt = (Object[]) this.projAttrs.get(index);
+ projAtt[1] = aggFunc;
+ }
+ }
+
+ @Override
+ protected void doTreeTransformation(ExecutionContext context)
+ throws AmbiguousNameException, TypeMismatchException,
+ NameResolutionException {
+ if (!this.transformationDone) {
+ checkAllProjectedFieldsInGroupBy(context);
+ this.cachedElementTypeForOrderBy = prepareResultType(context);
+ if (this.groupBy != null && !this.groupBy.isEmpty()) {
+ this.modifyGroupByToOrderBy(false, context);
+ }
+ if(this.originalOrderByClause != null) {
+ this.mapOriginalOrderByColumns(context);
+ }
+ }
+ this.transformationDone = true;
+ }
+
+ private void mapOriginalOrderByColumns(ExecutionContext context)
+ throws AmbiguousNameException, TypeMismatchException,
+ NameResolutionException {
+ this.revertAggregateFunctionInProjection();
+ Iterator<CompiledSortCriterion> iter = this.originalOrderByClause.iterator();
+ while (iter.hasNext()) {
+ CompiledSortCriterion csc = iter.next();
+ if (!csc.mapExpressionToProjectionField(this.projAttrs, context)) {
+ throw new QueryInvalidException(LocalizedStrings.DefaultQuery_ORDER_BY_ATTRIBS_NOT_PRESENT_IN_PROJ.toLocalizedString());
+ }
+ }
+ this.replaceAggregateFunctionInProjection();
+
+ }
+
+ @Override
+ public SelectResults evaluate(ExecutionContext context)
+ throws FunctionDomainException, TypeMismatchException,
+ NameResolutionException, QueryInvocationTargetException {
+ SelectResults sr = super.evaluate(context);
+ return this.applyAggregateAndGroupBy(sr, context);
+
+ }
+
+ public SelectResults applyAggregateAndGroupBy(SelectResults baseResults,
+ ExecutionContext context) throws FunctionDomainException,
+ TypeMismatchException, NameResolutionException,
+ QueryInvocationTargetException {
+ ObjectType elementType = baseResults.getCollectionType().getElementType();
+ boolean isStruct = elementType != null && elementType.isStructType();
+ boolean isBucketNodes = context.getBucketList() != null;
+ boolean createOrderedResultSet = isBucketNodes && this.orderByAttrs != null;
+ boolean[] objectChangedMarker = new boolean[]{false};
+ int limitValue = evaluateLimitValue(context, limit);
+ SelectResults newResults = createResultSet(context, elementType, isStruct,
+ createOrderedResultSet);
+ Aggregator[] aggregators = new Aggregator[this.aggregateFunctions.length];
+ refreshAggregators(aggregators, context);
+ if (this.orderByAttrs != null) {
+ applyGroupBy(baseResults, context, isStruct, newResults, aggregators,
+ !createOrderedResultSet, objectChangedMarker, limitValue);
+ } else {
+ Iterator iter = baseResults.iterator();
+ Object current = null;
+ boolean unterminated = iter.hasNext();
+ while (iter.hasNext()) {
+ current = iter.next();
+ accumulate(isStruct, aggregators, current, objectChangedMarker);
+ }
+ if (unterminated) {
+ this.terminateAndAddToResults(isStruct, newResults, aggregators,
+ current, context, !createOrderedResultSet, limitValue);
+ }
+ }
+
+ return newResults;
+ }
+
+ private SelectResults createResultSet(ExecutionContext context,
+ ObjectType elementType, boolean isStruct, boolean createOrderedResults) {
+ elementType = createNewElementType(elementType, isStruct);
+ SelectResults newResults;
+
+ //boolean isBucketNodes = context.getBucketList() != null;
+ boolean isPrQueryNode = context.getIsPRQueryNode();
+ // If it is bucket nodes query, we need to return ordered data
+ if (isStruct) {
+ if (createOrderedResults) {
+ newResults = new SortedResultsBag((StructTypeImpl) elementType, true);
+ } else {
+ if(this.originalOrderByClause != null) {
+ Comparator comparator = new OrderByComparator(this.originalOrderByClause, elementType, context);
+ newResults = new SortedStructBag(comparator, (StructType)elementType,
+ !this.originalOrderByClause.get(0).getCriterion());
+ }else {
+ newResults = QueryUtils.createStructCollection(this.isDistinct,
+ (StructType) elementType, context);
+ }
+ }
+ } else {
+ if (createOrderedResults) {
+ newResults = new SortedResultsBag(elementType, true);
+ } else {
+ if(this.originalOrderByClause != null) {
+ Comparator comparator = new OrderByComparator(this.originalOrderByClause, elementType, context);
+ newResults = new SortedResultsBag(comparator,elementType,
+ !this.originalOrderByClause.get(0).getCriterion());
+ }else {
+ newResults = QueryUtils.createResultCollection(this.isDistinct,
+ elementType, context);
+ }
+
+ }
+
+ }
+ return newResults;
+ }
+
+ private ObjectType createNewElementType(ObjectType elementType,
+ boolean isStruct) {
+ if (isStruct) {
+ StructType oldType = (StructType) elementType;
+ if (this.aggregateFunctions.length > 0) {
+ ObjectType[] oldFieldTypes = oldType.getFieldTypes();
+ ObjectType[] newFieldTypes = new ObjectType[oldFieldTypes.length];
+ int i = 0;
+ int aggFuncIndex = 0;
+ for (ObjectType oldFieldType : oldFieldTypes) {
+ if (this.aggregateColsPos.get(i)) {
+ newFieldTypes[i] = this.aggregateFunctions[aggFuncIndex++]
+ .getObjectType();
+ } else {
+ newFieldTypes[i] = oldFieldType;
+ }
+ ++i;
+ }
+ return new StructTypeImpl(oldType.getFieldNames(), newFieldTypes);
+ } else {
+ return oldType;
+ }
+ } else {
+ return this.aggregateFunctions.length > 0 ? this.aggregateFunctions[0]
+ .getObjectType() : elementType;
+ }
+ }
+
+ private void applyGroupBy(SelectResults baseResults,
+ ExecutionContext context, boolean isStruct, SelectResults newResults,
+ Aggregator[] aggregators, boolean isStructFields, boolean[] objectChangedMarker,
+ int limitValue)
+ throws FunctionDomainException, TypeMismatchException,
+ NameResolutionException, QueryInvocationTargetException {
+ Iterator iter = baseResults.iterator();
+ Object[] orderByTupleHolderCurrent = null;
+ Object[] orderByTupleHolderPrev = null;
+ Object orderByCurrent = null;
+ Object orderByPrev = null;
+
+ boolean isSingleOrderBy = this.orderByAttrs.size() <= 1;
+ if (!isSingleOrderBy) {
+ orderByTupleHolderPrev = new Object[orderByAttrs.size()];
+ orderByTupleHolderCurrent = new Object[orderByAttrs.size()];
+ }
+ boolean isFirst = true;
+ Object prev = null;
+ boolean unterminated = false;
+ boolean keepAdding = true;
+ while (iter.hasNext() && keepAdding) {
+ Object current = iter.next();
+ if (isSingleOrderBy) {
+ orderByCurrent = this.getOrderByEvaluatedTuple(context,
+ isSingleOrderBy, null,
+ isStruct ? ((Struct) current).getFieldValues() : current, objectChangedMarker);
+ } else {
+ orderByTupleHolderCurrent = (Object[]) this.getOrderByEvaluatedTuple(
+ context, isSingleOrderBy, orderByTupleHolderCurrent,
+ isStruct ? ((Struct) current).getFieldValues() : current, objectChangedMarker);
+ }
+ if (isFirst
+ || areOrderByTupleEqual(isSingleOrderBy, orderByPrev, orderByCurrent,
+ orderByTupleHolderPrev, orderByTupleHolderCurrent)) {
+ accumulate(isStruct, aggregators, current, objectChangedMarker);
+ unterminated = true;
+ isFirst = false;
+ } else {
+ keepAdding = terminateAndAddToResults(isStruct, newResults, aggregators, prev,
+ context, isStructFields, limitValue);
+ this.accumulate(isStruct, aggregators, current, objectChangedMarker);
+ unterminated = true;
+ }
+ // swap the holder arrays
+ Object[] temp = orderByTupleHolderCurrent;
+ orderByTupleHolderCurrent = orderByTupleHolderPrev;
+ orderByTupleHolderPrev = temp;
+ orderByPrev = orderByCurrent;
+ prev = current;
+ }
+ if (unterminated && keepAdding) {
+ this.terminateAndAddToResults(isStruct, newResults, aggregators, prev,
+ context, isStructFields, limitValue);
+ }
+
+ if(this.originalOrderByClause != null && limitValue > 0
+ && (context.getIsPRQueryNode() || context.getBucketList() == null)
+ ) {
+ ((Bag)newResults).applyLimit(limitValue);
+ }
+ }
+
+ private boolean terminateAndAddToResults(boolean isStruct,
+ SelectResults newResults, Aggregator[] aggregators, Object prev,
+ ExecutionContext context, boolean isStrucFields, int limitValue)
+ throws FunctionDomainException, TypeMismatchException,
+ NameResolutionException, QueryInvocationTargetException {
+ Object[] newRowArray = isStruct ? copyStruct((Struct) prev) : null;
+ Object newObject = null;
+ int bitstart = 0;
+ if(limitValue == 0) {
+ return false;
+ }
+
+ for (Aggregator aggregator : aggregators) {
+ if (isStruct) {
+ int pos = this.aggregateColsPos.nextSetBit(bitstart);
+ bitstart = pos + 1;
+ Object scalarResult = aggregator.terminate();
+ newRowArray[pos] = scalarResult;
+ } else {
+ newObject = aggregator.terminate();
+ }
+ }
+
+ if (isStruct) {
+ if (isStrucFields) {
+ ((StructFields) newResults).addFieldValues(newRowArray);
+ } else {
+ newResults.add(new StructImpl((StructTypeImpl) ((Struct) prev)
+ .getStructType(), newRowArray));
+ }
+ } else {
+ newResults.add(newObject);
+ }
+ boolean keepAdding = true;
+ if(this.originalOrderByClause == null && limitValue > 0
+ && (context.getIsPRQueryNode() || context.getBucketList() == null)
+ && newResults.size() == limitValue) {
+ keepAdding = false;
+ }
+ // rfresh the aggregators
+ refreshAggregators(aggregators, context);
+ return keepAdding;
+ }
+
+ private void refreshAggregators(Aggregator[] aggregators,
+ ExecutionContext context) throws FunctionDomainException,
+ TypeMismatchException, NameResolutionException,
+ QueryInvocationTargetException {
+ int i = 0;
+ for (CompiledAggregateFunction aggFunc : this.aggregateFunctions) {
+ Aggregator agg = (Aggregator) aggFunc.evaluate(context);
+ aggregators[i++] = agg;
+ }
+ }
+
+ private Object[] copyStruct(Struct struct) {
+ Object[] prevValues = struct.getFieldValues();
+ Object[] newRow = new Object[prevValues.length];
+ System.arraycopy(prevValues, 0, newRow, 0, prevValues.length);
+ return newRow;
+ }
+
+ private void accumulate(boolean isStruct, Aggregator[] aggregators,
+ Object current, boolean[] objectChangedMarker) {
+ int bitstart = 0;
+ for (Aggregator aggregator : aggregators) {
+ if (isStruct) {
+ int pos = this.aggregateColsPos.nextSetBit(bitstart);
+ bitstart = pos + 1;
+ Struct struct = (Struct) current;
+ Object scalar = PDXUtils.convertPDX(struct.getFieldValues()[pos], false, true, true, true, objectChangedMarker, isStruct);
+
+ aggregator.accumulate(scalar);
+ } else {
+ current = PDXUtils.convertPDX(current, false, true, true, true, objectChangedMarker, isStruct);
+ aggregator.accumulate(current);
+ }
+ }
+ }
+
+ private boolean areOrderByTupleEqual(boolean isSingleOrderBy, Object prev,
+ Object current, Object[] prevHolder, Object[] currentHolder) {
+ if (isSingleOrderBy) {
+ if (prev == null && current == null) {
+ return true;
+ } else if (prev != null) {
+ return prev.equals(current);
+ } else {
+ return current.equals(prev);
+ }
+ } else {
+ return Arrays.equals(prevHolder, currentHolder);
+ }
+
+ }
+
+ private Object getOrderByEvaluatedTuple(ExecutionContext context,
+ boolean isOrderByTupleSingle, Object[] holder, Object data, boolean[] objectChangedMarker) {
+ if (isOrderByTupleSingle) {
+ return PDXUtils.convertPDX(this.orderByAttrs.get(0).evaluate(data, context),
+ false, true, true, true, objectChangedMarker, false);
+ } else {
+ int i = 0;
+ for (CompiledSortCriterion csc : this.orderByAttrs) {
+ holder[i++] = PDXUtils.convertPDX(csc.evaluate(data, context), false, true, true, true, objectChangedMarker, false);
+ }
+ return holder;
+ }
+ }
+
+ @Override
+ public boolean isGroupBy() {
+ return true;
+ }
+
+ private void checkAllProjectedFieldsInGroupBy(ExecutionContext context)
+ throws AmbiguousNameException, TypeMismatchException,
+ NameResolutionException {
+ int index = 0;
+ for (Object o : this.projAttrs) {
+ Object[] projElem = (Object[]) o;
+ // if the projection is aggregate expression skip validating
+ if (!this.aggregateColsPos.get(index)) {
+ if (!checkProjectionInGroupBy(projElem, context)) {
+ throw new QueryInvalidException(
+ LocalizedStrings.DefaultQuery_PROJ_COL_ABSENT_IN_GROUP_BY
+ .toLocalizedString());
+ }
+ }
+ ++index;
+ }
+
+ // check if all the group by fields are present in projected columns
+ if (this.groupBy != null) {
+ int numGroupCols = this.groupBy != null ? this.groupBy.size() : 0;
+ int numColsInProj = this.projAttrs.size();
+ numColsInProj -= this.aggregateFunctions.length;
+ if (numGroupCols != numColsInProj) {
+ throw new QueryInvalidException(
+ LocalizedStrings.DefaultQuery_GROUP_BY_COL_ABSENT_IN_PROJ
+ .toLocalizedString());
+ }
+ }
+ }
+
+ private boolean checkProjectionInGroupBy(Object[] projElem,
+ ExecutionContext context) throws AmbiguousNameException,
+ TypeMismatchException, NameResolutionException {
+ boolean found = false;
+ StringBuffer projAttribBuffer = new StringBuffer();
+ CompiledValue cvProj = (CompiledValue) TypeUtils.checkCast(projElem[1],
+ CompiledValue.class);
+ cvProj.generateCanonicalizedExpression(projAttribBuffer, context);
+ String projAttribStr = projAttribBuffer.toString();
+ if (this.groupBy != null) {
+ for (CompiledValue grpBy : this.groupBy) {
+ if (grpBy.getType() == OQLLexerTokenTypes.Identifier) {
+ if (projElem[0] != null
+ && projElem[0].equals(((CompiledID) grpBy).getId())) {
+ found = true;
+ break;
+ }
+ }
+
+ // the grpup by expr is not an alias check for path
+ StringBuffer groupByExprBuffer = new StringBuffer();
+ grpBy.generateCanonicalizedExpression(groupByExprBuffer, context);
+ final String grpByExprStr = groupByExprBuffer.toString();
+
+ if (projAttribStr.equals(grpByExprStr)) {
+
+ found = true;
+ break;
+ }
+ }
+ }
+ return found;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledIn.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledIn.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledIn.java
index f5bfc71..bfe00ce 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledIn.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledIn.java
@@ -29,6 +29,7 @@ import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
import com.gemstone.gemfire.cache.query.QueryService;
import com.gemstone.gemfire.cache.query.RegionNotFoundException;
import com.gemstone.gemfire.cache.query.SelectResults;
+import com.gemstone.gemfire.cache.query.Struct;
import com.gemstone.gemfire.cache.query.TypeMismatchException;
import com.gemstone.gemfire.cache.query.internal.index.IndexData;
import com.gemstone.gemfire.cache.query.internal.index.IndexProtocol;
@@ -545,11 +546,13 @@ public class CompiledIn extends AbstractCompiledValue implements Indexable {
else {
indexFieldsSize = 1;
}
- boolean useLinkedSet = false;
+ boolean useLinkedDataStructure = false;
+ boolean nullValuesAtStart = true;
Boolean orderByClause = (Boolean)context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
if(orderByClause != null && orderByClause.booleanValue()) {
List orderByAttrs = (List)context.cacheGet(CompiledValue.ORDERBY_ATTRIB);
- useLinkedSet =orderByAttrs.size()==1;
+ useLinkedDataStructure =orderByAttrs.size()==1;
+ nullValuesAtStart = !((CompiledSortCriterion)orderByAttrs.get(0)).getCriterion();
}
List projAttrib = null;
@@ -567,11 +570,11 @@ public class CompiledIn extends AbstractCompiledValue implements Indexable {
if (resultType instanceof StructType) {
context.getCache().getLogger().fine(
"StructType resultType.class=" + resultType.getClass().getName());
- if(useLinkedSet) {
- results = new LinkedStructSet((StructTypeImpl)resultType);
+ if(useLinkedDataStructure) {
+ results = context.isDistinct() ? new LinkedStructSet((StructTypeImpl)resultType)
+ : new SortedResultsBag<Struct>((StructTypeImpl)resultType, nullValuesAtStart);
}else {
- results = new StructBag((StructTypeImpl)resultType,
- context.getCachePerfStats());
+ results = QueryUtils.createStructCollection(context, (StructTypeImpl)resultType);
}
indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
}
@@ -579,10 +582,11 @@ public class CompiledIn extends AbstractCompiledValue implements Indexable {
context.getCache().getLogger().fine(
"non-StructType resultType.class="
+ resultType.getClass().getName());
- if (useLinkedSet) {
- results = new LinkedResultSet(resultType);
+ if (useLinkedDataStructure) {
+ results = context.isDistinct() ? new LinkedResultSet(resultType) :
+ new SortedResultsBag(resultType, nullValuesAtStart);
} else {
- results = new ResultsBag(resultType, context.getCachePerfStats());
+ results = QueryUtils.createResultCollection(context, resultType) ;
}
indexFieldsSize = 1;
}
@@ -596,11 +600,11 @@ public class CompiledIn extends AbstractCompiledValue implements Indexable {
context.getCache().getLogger().fine(
"StructType resultType.class="
+ resultType.getClass().getName());
- if (useLinkedSet) {
- results = new LinkedStructSet((StructTypeImpl)resultType);
+ if (useLinkedDataStructure) {
+ results = context.isDistinct() ? new LinkedStructSet((StructTypeImpl)resultType)
+ :new SortedResultsBag<Struct>((StructTypeImpl)resultType, nullValuesAtStart);
} else {
- results = (SelectResults)new StructBag((StructTypeImpl)resultType,
- context.getCachePerfStats());
+ results = QueryUtils.createStructCollection(context, (StructTypeImpl)resultType) ;
}
indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
}
@@ -608,10 +612,11 @@ public class CompiledIn extends AbstractCompiledValue implements Indexable {
context.getCache().getLogger().fine(
"non-StructType resultType.class="
+ resultType.getClass().getName());
- if (useLinkedSet) {
- results = new LinkedResultSet(resultType);
+ if (useLinkedDataStructure) {
+ results = context.isDistinct() ? new LinkedResultSet(resultType) :
+ new SortedResultsBag(resultType, nullValuesAtStart);
} else {
- results = new ResultsBag(resultType, context.getCachePerfStats());
+ results = QueryUtils.createResultCollection(context, resultType) ;
}
indexFieldsSize = 1;
}
@@ -622,11 +627,11 @@ public class CompiledIn extends AbstractCompiledValue implements Indexable {
if (resultType instanceof StructType) {
context.getCache().getLogger().fine(
"StructType resultType.class=" + resultType.getClass().getName());
- if (useLinkedSet) {
- results = new LinkedStructSet((StructTypeImpl)resultType);
+ if (useLinkedDataStructure) {
+ results = context.isDistinct() ? new LinkedStructSet((StructTypeImpl)resultType) :
+ new SortedResultsBag<Struct>((StructTypeImpl)resultType, nullValuesAtStart);
} else {
- results = new StructBag((StructTypeImpl)resultType,
- context.getCachePerfStats());
+ results = QueryUtils.createStructCollection(context, (StructTypeImpl)resultType) ;
}
indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
}
@@ -634,10 +639,11 @@ public class CompiledIn extends AbstractCompiledValue implements Indexable {
context.getCache().getLogger().fine(
"non-StructType resultType.class="
+ resultType.getClass().getName());
- if (useLinkedSet) {
- results = new LinkedResultSet(resultType);
+ if (useLinkedDataStructure) {
+ results = context.isDistinct() ? new LinkedResultSet(resultType) :
+ new SortedResultsBag(resultType, nullValuesAtStart);
} else {
- results = new ResultsBag(resultType, context.getCachePerfStats());
+ results = QueryUtils.createResultCollection(context,resultType);
}
indexFieldsSize = 1;
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledJunction.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledJunction.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledJunction.java
index 820cbba..789d7df 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledJunction.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledJunction.java
@@ -364,9 +364,14 @@ public class CompiledJunction extends AbstractCompiledValue implements
currentIters.toArray(rIters);
ObjectType elementType = intermediateResults.getCollectionType()
.getElementType();
- SelectResults resultSet = (elementType.isStructType()) ? ((SelectResults) new StructBag(
- (StructTypeImpl) elementType, context.getCachePerfStats()))
- : ((SelectResults) new ResultsBag(elementType, context.getCachePerfStats()));
+ SelectResults resultSet ;
+ if(elementType.isStructType()) {
+ resultSet = QueryUtils.createStructCollection(context, (StructTypeImpl) elementType) ;
+ }else {
+ resultSet = QueryUtils.createResultCollection(context, elementType);
+ }
+
+
QueryObserver observer = QueryObserverHolder.getInstance();
try {
observer.startIteration(intermediateResults, operand);
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledSelect.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledSelect.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledSelect.java
index 878084b..be06404 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledSelect.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledSelect.java
@@ -8,17 +8,11 @@
*/
package com.gemstone.gemfire.cache.query.internal;
-import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
-
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
-import java.util.TreeSet;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheClosedException;
@@ -29,6 +23,7 @@ import com.gemstone.gemfire.cache.query.FunctionDomainException;
import com.gemstone.gemfire.cache.query.Index;
import com.gemstone.gemfire.cache.query.NameNotFoundException;
import com.gemstone.gemfire.cache.query.NameResolutionException;
+import com.gemstone.gemfire.cache.query.QueryInvalidException;
import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
import com.gemstone.gemfire.cache.query.QueryService;
import com.gemstone.gemfire.cache.query.RegionNotFoundException;
@@ -56,10 +51,10 @@ import com.gemstone.gemfire.pdx.internal.PdxString;
*/
public class CompiledSelect extends AbstractCompiledValue {
- private List orderByAttrs; //order by attributes: list of CompiledValue
+ protected List<CompiledSortCriterion> orderByAttrs; //order by attributes: list of CompiledValue
private CompiledValue whereClause; // can be null if there isn't one
private List iterators; // fromClause: list of CompiledIteratorDefs
- private List projAttrs; //projection attributes: list of Object[2]:
+ protected List projAttrs; //projection attributes: list of Object[2]:
// 0 is projection name, 1 is the CompiledValue for the expression
private boolean distinct;
private boolean count;
@@ -70,8 +65,13 @@ public class CompiledSelect extends AbstractCompiledValue {
// count(*) non-distinct queries where no indexes are used.
private int countStartQueryResult = 0;
+ protected List<CompiledValue> groupBy = null;
//Are not serialized and are recreated when compiling the query
- private ArrayList hints;
+ private List<String> hints;
+ protected boolean transformationDone = false;
+ protected ObjectType cachedElementTypeForOrderBy = null;
+ private boolean hasUnmappedOrderByCols = false;
+
/**
* Identifies the scope ID assosciated with the Select. The CompiledSelect object
@@ -83,7 +83,8 @@ public class CompiledSelect extends AbstractCompiledValue {
* Asif
*/
public CompiledSelect(boolean distinct, boolean count, CompiledValue whereClause,
- List iterators, List projAttrs,List orderByAttrs, CompiledValue limit, ArrayList hints) {
+ List iterators, List projAttrs,List<CompiledSortCriterion> orderByAttrs, CompiledValue limit,
+ List<String> hints, List<CompiledValue> groupByClause) {
this.orderByAttrs = orderByAttrs;
this.whereClause = whereClause;
this.iterators = iterators;
@@ -92,6 +93,8 @@ public class CompiledSelect extends AbstractCompiledValue {
this.count = count;
this.limit = limit;
this.hints = hints;
+ this.groupBy = groupByClause;
+
}
@Override
@@ -120,6 +123,14 @@ public class CompiledSelect extends AbstractCompiledValue {
public boolean isDistinct() {
return this.distinct;
}
+
+ public boolean isGroupBy() {
+ return this.groupBy != null;
+ }
+
+ public boolean isOrderBy() {
+ return this.orderByAttrs != null;
+ }
public void setDistinct(boolean distinct) {
this.distinct = distinct;
@@ -148,7 +159,7 @@ public class CompiledSelect extends AbstractCompiledValue {
return this.projAttrs;
}
- public List getOrderByAttrs() {
+ public List<CompiledSortCriterion> getOrderByAttrs() {
return this.orderByAttrs;
}
@@ -175,6 +186,7 @@ public class CompiledSelect extends AbstractCompiledValue {
context.addToIndependentRuntimeItrMap(iterDef);
context.bindIterator(rIter);
}
+
// is the where clause dependent on itr?
if (this.whereClause != null) {
context.addDependencies(this, this.whereClause.computeDependencies(context));
@@ -190,8 +202,11 @@ public class CompiledSelect extends AbstractCompiledValue {
CompiledValue prjExpr = (CompiledValue) TypeUtils.checkCast(prj[1], CompiledValue.class);
totalDependencySet = context.addDependencies(this, prjExpr.computeDependencies(context));
}
+ this.doTreeTransformation(context);
+
return totalDependencySet;
}else {
+ this.doTreeTransformation(context);
return context.getDependencySet(this, true);
}
// is the where clause dependent on itr?
@@ -208,6 +223,136 @@ public class CompiledSelect extends AbstractCompiledValue {
context.popScope();
}
}
+
+ protected void doTreeTransformation(ExecutionContext context) throws AmbiguousNameException, TypeMismatchException, NameResolutionException {
+ if(!this.transformationDone) {
+ this.cachedElementTypeForOrderBy = prepareResultType(context);
+ this.mapOrderByColumns(context);
+ this.transformGroupByIfPossible(context);
+ }
+ this.transformationDone = true;
+ }
+
+ /**
+ * Transforms the group by clause into distinct order by clause, if possible
+ * @param context
+ * @throws AmbiguousNameException
+ * @throws TypeMismatchException
+ * @throws NameResolutionException
+ */
+ private void transformGroupByIfPossible(ExecutionContext context)
+ throws AmbiguousNameException, TypeMismatchException, NameResolutionException {
+ //for time being assume that the group by cols are explicitly mentioned in proj
+ if(this.groupBy != null) {
+ List projAttribs = this.projAttrs;
+ if(projAttribs == null) {
+ projAttribs = new ArrayList();
+ List currentIters = context.getCurrentIterators();
+ for(Object o: currentIters) {
+ RuntimeIterator rIter = (RuntimeIterator)o;
+ String name = rIter.getName();
+ projAttribs.add(new Object[]{name, rIter});
+ }
+ }
+
+ if(projAttribs != null && projAttribs.size() != this.groupBy.size()) {
+ throw new QueryInvalidException(
+ LocalizedStrings.DefaultQuery_PROJ_COL_ABSENT_IN_GROUP_BY.toLocalizedString() +" or "
+ + LocalizedStrings.DefaultQuery_GROUP_BY_COL_ABSENT_IN_PROJ.toLocalizedString());
+ }
+
+ boolean shouldTransform = true;
+ StringBuffer lhsBuffer = new StringBuffer();
+ StringBuffer rhsBuffer = new StringBuffer();
+
+ outer :for(int i = 0; i < projAttribs.size() ; ++i) {
+ Object[] prj = (Object[]) TypeUtils.checkCast(projAttribs.get(i), Object[].class);
+ CompiledValue groupByAttr = this.groupBy.get(i);
+ if(prj[0] != null) {
+ if( groupByAttr instanceof CompiledID ) {
+ if (prj[0].equals(((CompiledID)groupByAttr).getId())) {
+ lhsBuffer.delete(0,lhsBuffer.length());
+ rhsBuffer.delete(0,rhsBuffer.length());
+ continue;
+ }
+ }
+ }
+ CompiledValue cvProj = (CompiledValue) TypeUtils.checkCast(prj[1], CompiledValue.class);
+ cvProj.generateCanonicalizedExpression(lhsBuffer, context);
+ groupByAttr.generateCanonicalizedExpression(rhsBuffer, context);
+ if(lhsBuffer.length() == rhsBuffer.length()) {
+ for(int indx = 0; indx < lhsBuffer.length() ; ++indx) {
+ if(lhsBuffer.charAt(indx) != rhsBuffer.charAt(indx)) {
+ shouldTransform = false;
+ break outer;
+ }
+ }
+ }else {
+ shouldTransform = false;
+ break;
+ }
+
+ lhsBuffer.delete(0,lhsBuffer.length());
+ rhsBuffer.delete(0,rhsBuffer.length());
+
+ }
+ //check if the order by clause is null or order by clause is same as proj.
+ //for now check if order by is null
+ if(shouldTransform && this.orderByAttrs == null) {
+ this.modifyGroupByToOrderBy(true, context);
+ }else {
+ throw new QueryInvalidException(
+ LocalizedStrings.DefaultQuery_PROJ_COL_ABSENT_IN_GROUP_BY.toLocalizedString() +" or "
+ + LocalizedStrings.DefaultQuery_GROUP_BY_COL_ABSENT_IN_PROJ.toLocalizedString());
+ }
+ }
+ }
+
+ protected void modifyGroupByToOrderBy(boolean setDistinct, ExecutionContext context) throws AmbiguousNameException, TypeMismatchException, NameResolutionException {
+ if(setDistinct) {
+ this.distinct = setDistinct;
+ }
+ this.orderByAttrs = new ArrayList<CompiledSortCriterion>(this.groupBy.size());
+ int colIndex = 0;
+ for(CompiledValue cv : this.groupBy) {
+ CompiledSortCriterion csc = new CompiledSortCriterion(false, cv);
+ csc.mapExpressionToProjectionField(projAttrs, context) ;
+ this.orderByAttrs.add(csc);
+ }
+ this.groupBy = null;
+ }
+
+ private void mapOrderByColumns(ExecutionContext context)
+ throws AmbiguousNameException, TypeMismatchException,
+ NameResolutionException {
+ if (this.orderByAttrs != null) {
+ Iterator<CompiledSortCriterion> iter = this.orderByAttrs.iterator();
+ while (iter.hasNext()) {
+ CompiledSortCriterion csc = iter.next();
+
+ // Asif: Ideally for replicated regions, the requirement that
+ // projected columns should
+ // contain order by fields ( directly or derivable on it),
+ // is not needed. But for PR , the query gathers only projected
+ // columns, so applying order by on the query node
+ // will need order by values ( which we dont send). So this
+ // restriction is needed.
+ // Also if this restriction is assumed to be correct, then the order
+ // by comparator can be optimized as
+ // it does not need to keep the mapping of evaluated order by clause,
+ // for comparison
+ if (!csc.mapExpressionToProjectionField(this.projAttrs, context)) {
+ this.hasUnmappedOrderByCols = true;
+ }
+ }
+ }
+ }
+
+
+ private void evalCanonicalizedExpressionForCSC(CompiledSortCriterion csc, ExecutionContext context,
+ StringBuffer buffer) throws AmbiguousNameException, TypeMismatchException, NameResolutionException {
+ csc.getExpr().generateCanonicalizedExpression(buffer, context);
+ }
/* Gets the appropriate empty results set when outside of actual query evalutaion.
*
@@ -238,12 +383,19 @@ public class CompiledSelect extends AbstractCompiledValue {
return results;
}
- public Object evaluate(ExecutionContext context) throws FunctionDomainException, TypeMismatchException,
+ public ObjectType getElementTypeForOrderByQueries() {
+ return this.cachedElementTypeForOrderBy;
+ }
+
+ public SelectResults evaluate(ExecutionContext context) throws FunctionDomainException, TypeMismatchException,
NameResolutionException, QueryInvocationTargetException {
// context.newScope(context.getScopeID(this));
context.newScope(this.scopeID);
context.pushExecCache(scopeID);
context.setDistinct(this.distinct);
+ if(this.hasUnmappedOrderByCols && context.getBucketList() != null) {
+ throw new QueryInvalidException(LocalizedStrings.DefaultQuery_ORDER_BY_ATTRIBS_NOT_PRESENT_IN_PROJ.toLocalizedString());
+ }
if (hints != null) {
context.cachePut(QUERY_INDEX_HINTS, hints);
}
@@ -264,8 +416,8 @@ public class CompiledSelect extends AbstractCompiledValue {
//Though in our case it may not be an issue as the compute depedency phase must have
//already set the index id
}
- Integer limitValue = evaluateLimitValue(context);
- Object result = null;
+ Integer limitValue = evaluateLimitValue(context, this.limit);
+ SelectResults result = null;
boolean evalAsFilters = false;
if (this.whereClause == null) {
result = doIterationEvaluate(context, false);
@@ -308,7 +460,7 @@ public class CompiledSelect extends AbstractCompiledValue {
if(this.orderByAttrs != null && numInd == 1) {
CompiledSortCriterion csc = (CompiledSortCriterion)orderByAttrs.get(0);
StringBuffer preferredIndexCondn = new StringBuffer();
- csc.getExpr().generateCanonicalizedExpression(preferredIndexCondn, context);
+ this.evalCanonicalizedExpressionForCSC(csc, context, preferredIndexCondn);
context.cachePut(PREF_INDEX_COND, preferredIndexCondn.toString());
}
boolean unlock = true;
@@ -340,9 +492,8 @@ public class CompiledSelect extends AbstractCompiledValue {
StringBuffer temp = null;
if (this.orderByAttrs != null) {
temp = new StringBuffer();
- ((CompiledSortCriterion) this.orderByAttrs.get(0)).expr
- .generateCanonicalizedExpression(temp, context);
-
+ CompiledSortCriterion csc = (CompiledSortCriterion) this.orderByAttrs.get(0);
+ this.evalCanonicalizedExpressionForCSC(csc, context, temp);
}
boolean needsTopLevelOrdering = true;
@@ -378,7 +529,7 @@ public class CompiledSelect extends AbstractCompiledValue {
&& (this.orderByAttrs == null || (canApplyOrderByAtIndex && !needsTopLevelOrdering))
&& this.projAttrs != null) {
// Possibility of evaluating the resultset as filter itself
- ObjectType resultType = this.prepareResultType(context);
+ ObjectType resultType = this.cachedElementTypeForOrderBy != null? this.cachedElementTypeForOrderBy :this.prepareResultType(context);
context.cachePut(RESULT_TYPE, resultType);
context.cachePut(PROJ_ATTRIB, this.projAttrs);
}
@@ -389,7 +540,7 @@ public class CompiledSelect extends AbstractCompiledValue {
if (!(context.cacheGet(RESULT_TYPE) instanceof Boolean)) {
QueryObserverHolder.getInstance()
.beforeApplyingProjectionOnFilterEvaluatedResults(result);
- result = applyProjectionOnCollection(result, context,
+ result = applyProjectionOnCollection( result, context,
!needsTopLevelOrdering);
}
} else {
@@ -406,7 +557,9 @@ public class CompiledSelect extends AbstractCompiledValue {
}
}
}
- if (result == null) { return QueryService.UNDEFINED; }
+ //TODO:Asif: It does not appear that results would be null ever.
+ //if (result == null) { return QueryService.UNDEFINED; }
+ assert result != null;
// drop duplicates if this is DISTINCT
if (result instanceof SelectResults) {
SelectResults sr = (SelectResults) result;
@@ -424,14 +577,14 @@ public class CompiledSelect extends AbstractCompiledValue {
}
result = new ResultsCollectionWrapper(colnType.getElementType(), r, limitValue);
- if (r instanceof ResultsBag.SetView) {
+ if (r instanceof Bag.SetView) {
((ResultsCollectionWrapper)result).setModifiable(false);
}
}
else {
// SelectResults is of type
if (limitValue > -1) {
- ((ResultsBag)sr).applyLimit(limitValue);
+ ((Bag)sr).applyLimit(limitValue);
}
}
@@ -525,7 +678,7 @@ public class CompiledSelect extends AbstractCompiledValue {
}
}
- int getLimitValue(Object[] bindArguments) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
+ public int getLimitValue(Object[] bindArguments) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
//if evaluation of the limit fails, we default to no limit
return evaluateLimitValue(bindArguments);
}
@@ -535,10 +688,8 @@ public class CompiledSelect extends AbstractCompiledValue {
throws TypeMismatchException, FunctionDomainException, NameResolutionException,
QueryInvocationTargetException {
- SelectResults results = context.getResults();
- if (results == null) {
- results = prepareEmptyResultSet(context,false);
- }
+ SelectResults results = prepareEmptyResultSet(context,false);
+
//TODO:Asif: SELF : Work on limit implementation on bulk get
// check for bulk get optimization
if (evaluateWhereClause) {
@@ -704,7 +855,7 @@ public class CompiledSelect extends AbstractCompiledValue {
observer.beforeIterationEvaluation(rIter, currObj);
numElementsInResult = doNestedIterations(level + 1, results, context,
evaluateWhereClause, numElementsInResult);
- Integer limitValue = evaluateLimitValue(context);
+ Integer limitValue = evaluateLimitValue(context, this.limit);
if (this.orderByAttrs == null && limitValue > -1 && numElementsInResult == limitValue) {
break;
}
@@ -713,7 +864,7 @@ public class CompiledSelect extends AbstractCompiledValue {
return numElementsInResult;
}
- private Object applyProjectionOnCollection(Object resultSet,
+ private SelectResults applyProjectionOnCollection(SelectResults resultSet,
ExecutionContext context, boolean ignoreOrderBy) throws TypeMismatchException,
AmbiguousNameException, FunctionDomainException, NameResolutionException,
QueryInvocationTargetException {
@@ -741,10 +892,12 @@ public class CompiledSelect extends AbstractCompiledValue {
else {
int numElementsAdded = 0;
SelectResults pResultSet = prepareEmptyResultSet(context,ignoreOrderBy);
- if (resultSet instanceof StructBag) {
- Iterator resultsIter = ((StructBag)resultSet).iterator();
+ boolean isStructType = resultSet.getCollectionType().getElementType() != null
+ && resultSet.getCollectionType().getElementType().isStructType();
+ if (isStructType) {
+ Iterator resultsIter = resultSet.iterator();
// Apply limit if there is no order by.
- Integer limitValue = evaluateLimitValue(context);
+ Integer limitValue = evaluateLimitValue(context, this.limit);
while (( (this.orderByAttrs != null && !ignoreOrderBy)|| limitValue < 0 || (numElementsAdded < limitValue))
&& resultsIter.hasNext()) {
// Check if query execution on this thread is canceled.
@@ -767,7 +920,7 @@ public class CompiledSelect extends AbstractCompiledValue {
RuntimeIterator rIter = (RuntimeIterator)iterators.get(0);
Iterator resultsIter = ((SelectResults)resultSet).iterator();
// Apply limit if there is no order by.
- Integer limitValue = evaluateLimitValue(context);
+ Integer limitValue = evaluateLimitValue(context, this.limit);
while (( (this.orderByAttrs != null && !ignoreOrderBy) || limitValue < 0 || (numElementsAdded < limitValue))
&& resultsIter.hasNext()) {
rIter.setCurrent(resultsIter.next());
@@ -788,7 +941,7 @@ public class CompiledSelect extends AbstractCompiledValue {
private SelectResults prepareEmptyResultSet(ExecutionContext context, boolean ignoreOrderBy)
throws TypeMismatchException, AmbiguousNameException
- {
+ {
// Asif:if no projection attributes or '*'as projection attribute
// & more than one/RunTimeIterator then create a StrcutSet.
// If attribute is null or '*' & only one RuntimeIterator then create a
@@ -800,67 +953,77 @@ public class CompiledSelect extends AbstractCompiledValue {
// create StructSet which will contain root objects of all iterators in
// from clause
- ObjectType elementType = prepareResultType(context);
+ ObjectType elementType = this.cachedElementTypeForOrderBy != null ? this.cachedElementTypeForOrderBy
+ : prepareResultType(context);
SelectResults results;
if (this.distinct || !this.count) {
if (this.orderByAttrs != null) {
- if(!this.distinct) {
- throw new UnsupportedOperationException(LocalizedStrings.CompiledSelect_NONDISTINCT_ORDERBY_NOT_YET_SUPPORTED.toLocalizedString());
- }
+ boolean nullValuesAtStart = !((CompiledSortCriterion)orderByAttrs.get(0)).getCriterion();
if (elementType.isStructType()) {
- if(ignoreOrderBy) {
- results = new LinkedStructSet((StructTypeImpl)elementType);
- }else {
- results = new SortedStructSet(new OrderByComparator( (StructTypeImpl)elementType),(StructTypeImpl)elementType);
+ if (ignoreOrderBy) {
+ results = this.distinct ? new LinkedStructSet(
+ (StructTypeImpl) elementType) : new SortedResultsBag(
+ elementType, nullValuesAtStart);
+
+ } else {
+ OrderByComparator comparator = this.hasUnmappedOrderByCols ? new OrderByComparatorUnmapped(
+ this.orderByAttrs, (StructTypeImpl) elementType, context)
+ : new OrderByComparator(this.orderByAttrs,
+ (StructTypeImpl) elementType, context);
+ results = this.distinct ? new SortedStructSet(comparator,
+ (StructTypeImpl) elementType) : new SortedStructBag(comparator,
+ (StructTypeImpl) elementType, nullValuesAtStart);
+
}
} else {
- if(ignoreOrderBy) {
- results = new LinkedResultSet();
- }else {
- results = new SortedResultSet(new OrderByComparator(elementType));
+ if (ignoreOrderBy) {
+ results = this.distinct ? new LinkedResultSet()
+ : new SortedResultsBag(nullValuesAtStart);
+
+ } else {
+ OrderByComparator comparator = this.hasUnmappedOrderByCols ? new OrderByComparatorUnmapped(
+ this.orderByAttrs, elementType, context)
+ : new OrderByComparator(this.orderByAttrs, elementType, context);
+ results = this.distinct ? new SortedResultSet(comparator)
+ : new SortedResultsBag(comparator, nullValuesAtStart);
}
results.setElementType(elementType);
}
} else {
- if (elementType.isStructType()) {
- results = new StructBag((StructType)elementType, context.getCachePerfStats());
+ if (this.distinct) {
+ if (elementType.isStructType()) {
+ results = new StructSet((StructType) elementType);
+ } else {
+ results = new ResultsSet(elementType);
+ }
} else {
- results = new ResultsBag(elementType, context.getCachePerfStats());
+ if (elementType.isStructType()) {
+ results = new StructBag((StructType) elementType,
+ context.getCachePerfStats());
+ } else {
+ results = new ResultsBag(elementType, context.getCachePerfStats());
+ }
}
}
} else {
- // Shobhit: If its a 'COUNT' query and no End processing required Like for 'DISTINCT'
- // we can directly keep count in ResultSet and ResultBag is good enough for that.
- results = new ResultsBag(new ObjectTypeImpl(Integer.class), 1 /*initial capacity for count value*/, context.getCachePerfStats());
+ // Shobhit: If its a 'COUNT' query and no End processing required Like for
+ // 'DISTINCT'
+ // we can directly keep count in ResultSet and ResultBag is good enough
+ // for that.
+ results = new ResultsBag(new ObjectTypeImpl(Integer.class), 1 /*
+ * initial
+ * capacity
+ * for count
+ * value
+ */,
+ context.getCachePerfStats());
countStartQueryResult = 0;
-
- }
-
- return results;
-
- /*
- if (elementType.isStructType()) {
- if (this.orderByAttrs != null) { // sorted struct
- return prepareEmptySortedStructSet((StructTypeImpl)elementType);
- } else { // unsorted struct
- return new StructBag((StructType)elementType, context.getCachePerfStats());
- }
- }
- else { // non-struct
- if (this.orderByAttrs != null) { // sorted non-struct
- return prepareEmptySortedResultSet(elementType);
- } else { // unsorted non-struct
- return new ResultsBag(elementType, context.getCachePerfStats());
- }
+
}
- */
- /*
- return prepareEmptySelectResults(elementType, this.orderByAttrs != null,
- context);
- */
+ return results;
}
- public ObjectType prepareResultType(ExecutionContext context)
+ protected ObjectType prepareResultType(ExecutionContext context)
throws TypeMismatchException, AmbiguousNameException
{
// Asif:if no projection attributes or '*'as projection attribute
@@ -1005,48 +1168,46 @@ public class CompiledSelect extends AbstractCompiledValue {
+
private int applyProjectionAndAddToResultSet(ExecutionContext context,
- Object resultSet, boolean ignoreOrderBy) throws FunctionDomainException, TypeMismatchException,
+ SelectResults resultSet, boolean ignoreOrderBy) throws FunctionDomainException, TypeMismatchException,
NameResolutionException, QueryInvocationTargetException {
List currrentRuntimeIters = context.getCurrentIterators();
- // Asif : Code modified to fix the bug of incorrect composition of
- // ResultSet
- //boolean newAddition = false;
+
int occurence = 0;
- boolean isStructSet = resultSet instanceof StructSet;
- boolean isStructBag = resultSet instanceof StructBag;
- boolean isResultBag = resultSet instanceof ResultsBag;
- boolean isLinkedStructSet = resultSet instanceof LinkedStructSet;
- boolean isLinkedResultSet = resultSet instanceof LinkedResultSet;
- // @todo (resultSet instanceof SortedStructBag) ||
- boolean isSortedStructSet = resultSet instanceof SortedStructSet;
+ ObjectType elementType = resultSet.getCollectionType().getElementType();
+ boolean isStruct = elementType != null && elementType.isStructType();
+
+ //TODO : Asif : Optimize this condition in some clean way
+ boolean isLinkedStructure = resultSet instanceof Ordered && ((Ordered)resultSet).dataPreordered();
+
ArrayList evaluatedOrderByClause = null;
OrderByComparator comparator = null;
boolean applyOrderBy = false;
if (this.orderByAttrs != null && !ignoreOrderBy) {
- // In case PR order-by will get applied on the coordinator node
+ // In case PR order-by will get applied on the coordinator node
// on the cumulative results. Apply the order-by on PR only if
// limit is specified.
- Integer limitValue = evaluateLimitValue(context);
+ Integer limitValue = evaluateLimitValue(context, this.limit);
if (context.getPartitionedRegion() != null && limitValue < 0) {
applyOrderBy = false;
}
applyOrderBy = true;
}
-
+
if (this.orderByAttrs != null && !ignoreOrderBy) {
- comparator = (OrderByComparator)((TreeSet)resultSet).comparator();
+ comparator = (OrderByComparator) ((Ordered) resultSet).comparator();
}
if (projAttrs == null) {
int len = currrentRuntimeIters.size();
Object values[] = new Object[len];
for (int i = 0; i < len; i++) {
- RuntimeIterator iter = (RuntimeIterator)currrentRuntimeIters.get(i);
+ RuntimeIterator iter = (RuntimeIterator) currrentRuntimeIters.get(i);
values[i] = iter.evaluate(context);
// For local queries with distinct, deserialize all PdxInstances
// as we do not have a way to compare Pdx and non Pdx objects in case
// the cache has a mix of pdx and non pdx objects.
- // We still have to honor the cache level readserialized flag in
+ // We still have to honor the cache level readserialized flag in
// case of all Pdx objects in cache
if (this.distinct
&& !((DefaultQuery) context.getQuery()).isRemoteQuery()
@@ -1055,89 +1216,134 @@ public class CompiledSelect extends AbstractCompiledValue {
values[i] = ((PdxInstance) values[i]).getObject();
}
}
-
+
// Shobhit: Add count value to the counter for this select expression.
// Don't care about Order By for count(*).
if (isCount() && !this.distinct) {
- //Counter is local to CompileSelect and not available in ResultSet until
- //the end of evaluate call to this CompiledSelect object.
+ // Counter is local to CompileSelect and not available in ResultSet
+ // until
+ // the end of evaluate call to this CompiledSelect object.
this.countStartQueryResult++;
occurence = 1;
} else {
// if order by is present
if (applyOrderBy) {
StructImpl structImpl;
- evaluatedOrderByClause = evaluateSortCriteria(context, resultSet);
- if (isSortedStructSet) {
- if (values.length == 1 && values[0] instanceof StructImpl) {
- structImpl = (StructImpl)values[0];
- comparator.orderByMap.put(structImpl.getFieldValues(), evaluatedOrderByClause);
- occurence = ((SortedStructSet)resultSet).add(structImpl) ? 1 : 0;
+ if (this.distinct) {
+ if (isStruct) {
+ if (values.length == 1 && values[0] instanceof StructImpl) {
+ structImpl = (StructImpl) values[0];
+ comparator.addEvaluatedSortCriteria(
+ structImpl.getFieldValues(), context);
+ occurence = resultSet.add(structImpl) ? 1
+ : 0;
+ } else {
+ comparator.addEvaluatedSortCriteria(values, context);
+ occurence = ((StructFields) resultSet).addFieldValues(values) ? 1
+ : 0;
+ }
+ // Asif: TODO:Instead of a normal Map containing which holds
+ // StructImpl object
+ // use a THashObject with Object[] array hashing stragtegy as we
+ // are unnnecessarily
+ // creating objects of type Object[]
} else {
- comparator.orderByMap.put(values, evaluatedOrderByClause);
- occurence = ((SortedStructSet)resultSet).addFieldValues(values) ? 1 : 0;
- }
- //Asif: TODO:Instead of a normal Map containing which holds StructImpl object
- // use a THashObject with Object[] array hashing stragtegy as we are unnnecessarily
- //creating objects of type Object[]
- }
- else {
- comparator.orderByMap.put(values[0], evaluatedOrderByClause);
- occurence = ((SortedResultSet)resultSet).add(values[0]) ? 1 : 0;
+ comparator.addEvaluatedSortCriteria(values[0], context);
+ occurence = resultSet.add(values[0]) ? 1 : 0;
+ }
+ } else {
+ if (isStruct) {
+ if (values.length == 1 && values[0] instanceof StructImpl) {
+ structImpl = (StructImpl) values[0];
+ comparator.addEvaluatedSortCriteria(
+ structImpl.getFieldValues(), context);
+ occurence = ((Bag) resultSet).addAndGetOccurence(structImpl.getFieldValues());
+ } else {
+ comparator.addEvaluatedSortCriteria(values, context);
+ occurence = ((Bag) resultSet).addAndGetOccurence(values) ;
+
+ }
+ } else {
+ comparator.addEvaluatedSortCriteria(values[0], context);
+ occurence = ((Bag) resultSet)
+ .addAndGetOccurence(values[0]);
+ }
}
} else {
- if (isStructSet) {
- occurence = ((StructSet) resultSet).addFieldValues(values) ? 1 : 0;
- } else if (isStructBag) {
- occurence = ((ResultsBag) resultSet).addAndGetOccurence(values);
- } else if (isLinkedStructSet) {
- StructImpl structImpl;
- if (values.length == 1 && values[0] instanceof StructImpl) {
- structImpl = (StructImpl) values[0];
- } else {
- structImpl = new StructImpl(((LinkedStructSet) resultSet).structType, values);
+ if(isLinkedStructure) {
+ if(isStruct) {
+ StructImpl structImpl;
+ if (values.length == 1 && values[0] instanceof StructImpl) {
+ structImpl = (StructImpl) values[0];
+ } else {
+ structImpl = new StructImpl(
+ (StructTypeImpl)elementType, values);
+ }
+ if(this.distinct) {
+ occurence = resultSet.add(structImpl) ? 1 : 0;
+ }else {
+ occurence = ((Bag)resultSet).addAndGetOccurence(structImpl);
+ }
+ }else {
+ if(this.distinct) {
+ occurence = resultSet.add(values[0]) ? 1 : 0;
+ }else {
+ occurence = ((Bag)resultSet).addAndGetOccurence(values[0]);
+ }
+
}
- occurence = ((LinkedStructSet) resultSet).add(structImpl) ? 1 : 0;
- } else if (isLinkedResultSet) {
- occurence = ((LinkedResultSet) resultSet).add(values[0]) ? 1 : 0;
- } else if (isResultBag) {
- boolean add = true;
- if (context.isCqQueryContext()) {
- if (values[0] instanceof Region.Entry) {
- Region.Entry e = (Region.Entry) values[0];
- if (!e.isDestroyed()) {
- try {
- values[0] = new CqEntry(e.getKey(), e.getValue());
- } catch (EntryDestroyedException ede) {
- // Even though isDestory() check is made, the entry could
- // throw EntryDestroyedException if the value becomes null.
- add = false;
+ }
+ else {
+ if (this.distinct) {
+ if (isStruct) {
+ occurence = ((StructFields) resultSet).addFieldValues(values) ? 1
+ : 0;
+ } else {
+ occurence = resultSet.add(values[0]) ? 1 : 0;
+ }
+ } else {
+ if (isStruct) {
+ occurence = ((Bag) resultSet)
+ .addAndGetOccurence(values);
+ } else {
+ boolean add = true;
+ if (context.isCqQueryContext()) {
+ if (values[0] instanceof Region.Entry) {
+ Region.Entry e = (Region.Entry) values[0];
+ if (!e.isDestroyed()) {
+ try {
+ values[0] = new CqEntry(e.getKey(), e.getValue());
+ } catch (EntryDestroyedException ede) {
+ // Even though isDestory() check is made, the entry
+ // could
+ // throw EntryDestroyedException if the value becomes
+ // null.
+ add = false;
+ }
+ } else {
+ add = false;
+ }
}
- } else {
- add = false;
+ }
+ if (add) {
+ occurence = ((Bag) resultSet)
+ .addAndGetOccurence(values[0]);
}
}
}
- if (add) {
- occurence = ((ResultsBag) resultSet).addAndGetOccurence(values[0]);
- }
- } else {
- // Is a ResultsSet
- occurence = ((SelectResults) resultSet).add(values[0]) ? 1 : 0;
}
}
}
- }
- else { // One or more projection attributes
+ } else { // One or more projection attributes
int projCount = projAttrs.size();
Object[] values = new Object[projCount];
for (int i = 0; i < projCount; i++) {
- Object projDef[] = (Object[])projAttrs.get(i);
- values[i] = ((CompiledValue)projDef[1]).evaluate(context);
+ Object projDef[] = (Object[]) projAttrs.get(i);
+ values[i] = ((CompiledValue) projDef[1]).evaluate(context);
// For local queries with distinct, deserialize all PdxInstances
// as we do not have a way to compare Pdx and non Pdx objects in case
// the cache has a mix of pdx and non pdx objects.
- // We still have to honor the cache level readserialized flag in
+ // We still have to honor the cache level readserialized flag in
// case of all Pdx objects in cache.
// Also always convert PdxString to String before adding to resultset
// for remote queries
@@ -1150,42 +1356,65 @@ public class CompiledSelect extends AbstractCompiledValue {
}
}
}
-
- // if order by is present
+ // if order by is present
if (applyOrderBy) {
- evaluatedOrderByClause = evaluateSortCriteria(context, resultSet);
- if (isSortedStructSet) {
- comparator.orderByMap.put(values, evaluatedOrderByClause);
- //Asif: Occurence field is used to identify the corrcet number of iterations
- //required to implement the limit based on the presence or absence
- //of distinct clause
- occurence = ((SortedStructSet)resultSet).addFieldValues(values) ? 1 : 0;
- }
- else {
- comparator.orderByMap.put(values[0], evaluatedOrderByClause);
- occurence = ((SortedResultSet)resultSet).add(values[0]) ? 1 : 0;
- }
- }
- else {
- if (isStructSet) {
- occurence = ((StructSet)resultSet).addFieldValues(values) ? 1 : 0;
- }
- else if (isStructBag) {
- occurence = ((ResultsBag)resultSet).addAndGetOccurence(values);
- }else if(isLinkedStructSet) {
- StructImpl structImpl = new StructImpl(
- ((LinkedStructSet)resultSet).structType, values);;
-
- occurence = ((LinkedStructSet)resultSet).add(structImpl) ? 1 : 0;
- }else if(isLinkedResultSet) {
- occurence = ((LinkedResultSet)resultSet).add(values[0]) ? 1 : 0;
- }
- else if (isResultBag) {
- occurence = ((ResultsBag)resultSet).addAndGetOccurence(values[0]);
+ if (distinct) {
+ if (isStruct) {
+ comparator.addEvaluatedSortCriteria(values, context);
+ // Asif: Occurence field is used to identify the corrcet number of
+ // iterations
+ // required to implement the limit based on the presence or absence
+ // of distinct clause
+ occurence = ((StructFields) resultSet).addFieldValues(values) ? 1
+ : 0;
+ } else {
+ comparator.addEvaluatedSortCriteria(values[0], context);
+ occurence = resultSet.add(values[0]) ? 1 : 0;
+ }
+ } else {
+ if (isStruct) {
+ comparator.addEvaluatedSortCriteria(values, context);
+ occurence = ((Bag) resultSet).addAndGetOccurence(values);
+ } else {
+ comparator.addEvaluatedSortCriteria(values[0], context);
+ occurence = ((Bag) resultSet)
+ .addAndGetOccurence(values[0]);
+ }
}
- else {
- // Is a ResultsSet
- occurence = ((SelectResults)resultSet).add(values[0]) ? 1 : 0;
+ } else {
+ if(isLinkedStructure) {
+ if(isStruct) {
+ StructImpl structImpl = new StructImpl((StructTypeImpl)elementType, values);
+ if(this.distinct) {
+ occurence = resultSet.add(structImpl) ? 1 : 0;
+ }else {
+ occurence = ((Bag)resultSet).addAndGetOccurence(structImpl);
+ }
+
+ }else {
+ if(this.distinct) {
+ occurence = resultSet.add(values[0]) ? 1 : 0;
+ }else {
+ occurence = ((Bag)resultSet).addAndGetOccurence(values[0]);
+ }
+ }
+ }else {
+ if (this.distinct) {
+ if (isStruct) {
+ occurence = ((StructFields) resultSet).addFieldValues(values) ? 1
+ : 0;
+ } else {
+ occurence = resultSet.add(values[0]) ? 1 : 0;
+ }
+ } else {
+ if (isStruct) {
+ occurence = ((Bag) resultSet)
+ .addAndGetOccurence(values);
+ } else {
+ occurence = ((Bag) resultSet)
+ .addAndGetOccurence(values[0]);
+ }
+ }
}
}
}
@@ -1230,35 +1459,7 @@ public class CompiledSelect extends AbstractCompiledValue {
}
return name;
}
- /**
- * Yogesh : This methods evaluates sort criteria and returns a ArrayList of
- * Object[] arrays of evaluated criteria
- * @param context
- * @param sr
- * @return ArrayList
- * @throws FunctionDomainException
- * @throws TypeMismatchException
- * @throws NameResolutionException
- * @throws QueryInvocationTargetException
- */
- private ArrayList evaluateSortCriteria(ExecutionContext context, Object sr)
- throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
-
- CompiledSortCriterion csc ;
- ArrayList list = new ArrayList();
- if(orderByAttrs != null){
- Iterator orderiter = orderByAttrs.iterator();
- while (orderiter.hasNext()) {
- csc = (CompiledSortCriterion)orderiter.next();
- Object[] arr = new Object[2];
- arr[0] = csc.evaluate(context);
- arr[1] = Boolean.valueOf(csc.criterion);
- list.add(arr);
- }
-
- }
- return list;
- }
+
/**
* Optimized evaluate for CQ execution.
@@ -1351,10 +1552,10 @@ public class CompiledSelect extends AbstractCompiledValue {
return limitValue;
}
- private Integer evaluateLimitValue(ExecutionContext context) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
+ protected static Integer evaluateLimitValue(ExecutionContext context, CompiledValue limit) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
Integer limitValue = -1;
- if (this.limit != null) {
- limitValue = (Integer)this.limit.evaluate(context);
+ if (limit != null) {
+ limitValue = (Integer)limit.evaluate(context);
if (limitValue == null) {
//This is incase an object array was passed in but no param was set for the limit
limitValue = -1;
@@ -1365,155 +1566,10 @@ public class CompiledSelect extends AbstractCompiledValue {
private static class NullIteratorException extends Exception {
- }
-}
-
-/**
- * Yogesh : A generic comparator class which compares two Object/StructImpl according to
- * their sort criterion specified in order by clause
- */
-class OrderByComparator implements Comparator
-{
- /** a map of the form
- * <StructImpl/Object, List(Object[], Object[])>
- */
- final Map orderByMap ;
- private final ObjectType objType;
- public OrderByComparator(ObjectType objType) {
- this.objType = objType;
- if(objType.isStructType()) {
- orderByMap = new Object2ObjectOpenCustomHashMap(new StructBag.ObjectArrayFUHashingStrategy());
- }else {
- this.orderByMap = new HashMap();
- }
- }
+ }
- /**
- * Compares its two arguments for order. Returns a negative integer,
- * zero, or a positive integer as the first argument is less than, equal
- * to, or greater than the second.
- * @param obj1 the first object to be compared.
- * @param obj2 the second object to be compared.
- * @return a negative integer, zero, or a positive integer as the
- * first argument is less than, equal to, or greater than the
- * second.
- * @throws ClassCastException if the arguments' types prevent them from
- * being compared by this Comparator.
- */
- public int compare(Object obj1 , Object obj2){
- int result = -1;
- if (obj1 == null && obj2 == null) {
- return 0;
- }
-
- if ((this.objType.isStructType() && obj1 instanceof Object[] && obj2 instanceof Object[]) ||
- !this.objType.isStructType()){ // obj1 instanceof Object && obj2 instanceof Object){
- ArrayList list1 = (ArrayList)orderByMap.get(obj1);
- ArrayList list2 = (ArrayList)orderByMap.get(obj2);
-
- if(list1.size() != list2.size()){
- Support.assertionFailed("Error Occured due to improper sort criteria evaluation ");
- }else{
- for (int i=0; i< list1.size(); i++){
- Object arr1[] = (Object [])list1.get(i);
- Object arr2[] = (Object [])list2.get(i);
- // check for null.
- if (arr1[0] == null || arr2[0] == null) {
- if (arr1[0] == null) {
- result = (arr2[0] == null ? 0: -1);
- } else {
- result = 1;
- }
- } else if (arr1[0] == QueryService.UNDEFINED || arr2[0] == QueryService.UNDEFINED) {
- if (arr1[0] == QueryService.UNDEFINED) {
- result = (arr2[0] == QueryService.UNDEFINED ? 0: -1);
- } else {
- result = 1;
- }
- } else {
- if(arr1[0] instanceof PdxString && arr2[0] instanceof String){
- arr2[0] = new PdxString((String) arr2[0]);
- }
- else if(arr2[0] instanceof PdxString && arr1[0] instanceof String){
- arr1[0] = new PdxString((String) arr1[0]);
- }
- result = ((Comparable)arr1[0]).compareTo(arr2[0]);
- }
+}
- // equals.
- if (result == 0) {
- continue;
- } else {
- // not equal, change the sign based on the order by type (asc, desc).
- if(((Boolean)arr1[1]).booleanValue()) {
- result = (result * -1);
- }
- return result;
- }
- }
- //The comparable fields are equal, so we check if the overall keys are equal or not
- if(this.objType.isStructType()) {
- int i =0;
- for(Object o1:(Object[])obj1) {
- Object o2 = ((Object[])obj2)[i++];
- // Check for null value.
- if (o1 == null || o2 == null)
- {
- if (o1 == null) {
- if (o2 == null) {
- continue;
- }
- return -1;
- } else {
- return 1;
- }
- } else if (o1 == QueryService.UNDEFINED || o2 == QueryService.UNDEFINED) {
- if (o1 == QueryService.UNDEFINED) {
- if (o2 == QueryService.UNDEFINED) {
- continue;
- }
- return -1;
- } else {
- return 1;
- }
- }
- if (o1 instanceof Comparable) {
- if(o1 instanceof PdxString && o2 instanceof String){
- o2 = new PdxString((String) o2);
- }
- else if(o2 instanceof PdxString && o1 instanceof String){
- o1 = new PdxString((String) o1);
- }
- int rslt = ((Comparable) o1).compareTo(o2);
- if (rslt == 0) {
- continue;
- } else {
- return rslt;
- }
- } else if(!o1.equals(o2)) {
- return -1;
- }
- }
- return 0;
- }else {
- if(obj1 instanceof PdxString && obj2 instanceof String){
- obj2 = new PdxString((String) obj2);
- }
- else if(obj2 instanceof PdxString && obj1 instanceof String){
- obj1 = new PdxString((String) obj1);
- }
- if (obj1 instanceof Comparable) {
- return ((Comparable) obj1).compareTo(obj2);
- } else {
- return obj1.equals(obj2)?0:-1;
- }
- }
- }
- }
- return -1;
- }
-
-}