blob: 884bff997aab17a5821969124a5697c5081d8423 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.cache.query.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.geode.annotations.Immutable;
import org.apache.geode.cache.CacheException;
import org.apache.geode.cache.query.FunctionDomainException;
import org.apache.geode.cache.query.NameResolutionException;
import org.apache.geode.cache.query.QueryInvocationTargetException;
import org.apache.geode.cache.query.TypeMismatchException;
import org.apache.geode.cache.query.internal.parse.OQLLexerTokenTypes;
import org.apache.geode.cache.query.internal.types.TypeUtils;
import org.apache.geode.cache.query.types.ObjectType;
/**
* This class represents a compiled form of sort criterian present in order by clause
*/
public class CompiledSortCriterion extends AbstractCompiledValue {
// criterion true indicates descending order
private boolean criterion = false;
private CompiledValue expr = null;
int columnIndex = -1;
private CompiledValue originalCorrectedExpression = null;
@Override
public List getChildren() {
return Collections.singletonList(this.originalCorrectedExpression);
}
@Override
public int getType() {
return SORT_CRITERION;
}
/**
* evaluates sort criteria in order by clause
*/
public Object evaluate(Object data, ExecutionContext context) {
Object value;
if (this.columnIndex > 0) {
value = ((Object[]) data)[this.columnIndex];
} else if (this.columnIndex == 0) {
if (data instanceof Object[]) {
value = ((Object[]) data)[this.columnIndex];
} else {
value = data;
}
} else {
throw new IllegalStateException(" Order By Column attribute unmapped");
}
context.setCurrentProjectionField(value);
try {
return this.expr.evaluate(context);
} catch (Exception e) {
// TODO: never throw an anonymous inner class
throw new CacheException(e) {};
}
}
CompiledSortCriterion(boolean criterion, CompiledValue cv) {
this.expr = cv;
this.criterion = criterion;
this.originalCorrectedExpression = this.expr;
}
public boolean getCriterion() {
return criterion;
}
public CompiledValue getExpr() {
return this.originalCorrectedExpression;
}
public int getColumnIndex() {
return this.columnIndex;
}
@Override
public Object evaluate(ExecutionContext context) throws FunctionDomainException,
TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
return this.expr.evaluate(context);
}
private void substituteExpression(CompiledValue newExpression, int columnIndex) {
this.expr = newExpression;
this.columnIndex = columnIndex;
}
private void substituteExpressionWithProjectionField(int columnIndex) {
this.expr = ProjectionField.getProjectionField();
this.columnIndex = columnIndex;
}
private CompiledValue getReconstructedExpression(String projAttribStr, ExecutionContext context)
throws TypeMismatchException, NameResolutionException {
List<CompiledValue> expressions = PathUtils.collectCompiledValuesInThePath(expr, context);
StringBuilder tempBuff = new StringBuilder();
ListIterator<CompiledValue> listIter = expressions.listIterator(expressions.size());
while (listIter.hasPrevious()) {
listIter.previous().generateCanonicalizedExpression(tempBuff, context);
if (tempBuff.toString().equals(projAttribStr)) {
// we have found our match from where we have to replace the expression
break;
} else {
tempBuff.delete(0, tempBuff.length());
}
}
// Now we need to create a new CompiledValue which terminates with
// ProjectionField
CompiledValue cvToRetainTill = listIter.previous();
CompiledValue prevCV = null;
List<Object> reconstruct = new ArrayList<Object>();
CompiledValue cv = expressions.get(0);
int index = 0;
do {
prevCV = cv;
switch (cv.getType()) {
case OQLLexerTokenTypes.METHOD_INV:
reconstruct.add(0, ((CompiledOperation) cv).getArguments());
reconstruct.add(0, ((CompiledOperation) cv).getMethodName());
break;
case CompiledValue.PATH:
reconstruct.add(0, ((CompiledPath) cv).getTailID());
break;
case OQLLexerTokenTypes.TOK_LBRACK:
reconstruct.add(0, ((CompiledIndexOperation) cv).getExpression());
break;
default:
throw new IllegalStateException("Unexpected CompiledValue in order by clause");
}
reconstruct.add(0, prevCV.getType());
cv = expressions.get(++index);
} while (prevCV != cvToRetainTill);
// Now reconstruct back
Iterator<Object> iter = reconstruct.iterator();
CompiledValue currentValue = ProjectionField.getProjectionField();
while (iter.hasNext()) {
int type = (Integer) iter.next();
switch (type) {
case CompiledValue.PATH:
currentValue = new CompiledPath(currentValue, (String) iter.next());
break;
case OQLLexerTokenTypes.METHOD_INV:
currentValue =
new CompiledOperation(currentValue, (String) iter.next(), (List) iter.next());
break;
case OQLLexerTokenTypes.TOK_LBRACK:
currentValue = new CompiledIndexOperation(currentValue, (CompiledValue) iter.next());
break;
}
}
return currentValue;
}
boolean mapExpressionToProjectionField(List projAttrs, ExecutionContext context)
throws TypeMismatchException, NameResolutionException {
boolean mappedColumn = false;
this.originalCorrectedExpression = expr;
if (projAttrs != null) {
// if expr is CompiledID , check for alias
if (expr.getType() == OQLLexerTokenTypes.Identifier) {
for (int i = 0; i < projAttrs.size() && !mappedColumn; ++i) {
Object[] prj = (Object[]) TypeUtils.checkCast(projAttrs.get(i), Object[].class);
if (prj[0] != null && prj[0].equals(((CompiledID) expr).getId())) {
// set the field index
this.substituteExpressionWithProjectionField(i);
this.originalCorrectedExpression = (CompiledValue) prj[1];
mappedColumn = true;
}
}
}
if (!mappedColumn) {
// the order by expr is not an alias check for path
StringBuilder orderByExprBuffer = new StringBuilder(),
projAttribBuffer = new StringBuilder();
expr.generateCanonicalizedExpression(orderByExprBuffer, context);
final String orderByExprStr = orderByExprBuffer.toString();
for (int i = 0; i < projAttrs.size(); ++i) {
Object[] prj = (Object[]) TypeUtils.checkCast(projAttrs.get(i), Object[].class);
CompiledValue cvProj = (CompiledValue) TypeUtils.checkCast(prj[1], CompiledValue.class);
cvProj.generateCanonicalizedExpression(projAttribBuffer, context);
final String projAttribStr = projAttribBuffer.toString();
if (projAttribStr.equals(orderByExprStr)) {
// set the field index
this.substituteExpressionWithProjectionField(i);
mappedColumn = true;
break;
} else if (orderByExprStr.startsWith(projAttribStr)) {
CompiledValue newExpr = getReconstructedExpression(projAttribStr, context);
this.substituteExpression(newExpr, i);
mappedColumn = true;
break;
}
projAttribBuffer.delete(0, projAttribBuffer.length());
}
}
} else {
RuntimeIterator rIter = context.findRuntimeIterator(expr);
List currentIters = context.getCurrentIterators();
for (int i = 0; i < currentIters.size(); ++i) {
RuntimeIterator runtimeIter = (RuntimeIterator) currentIters.get(i);
if (runtimeIter == rIter) {
/* this.substituteExpressionWithProjectionField( i); */
StringBuilder temp = new StringBuilder();
rIter.generateCanonicalizedExpression(temp, context);
// this.correctedCanonicalizedExpression = temp.toString();
/* mappedColumn = true; */
String projAttribStr = temp.toString();
temp = new StringBuilder();
expr.generateCanonicalizedExpression(temp, context);
String orderbyStr = temp.toString();
if (projAttribStr.equals(orderbyStr)) {
this.substituteExpressionWithProjectionField(i);
mappedColumn = true;
break;
} else {
CompiledValue newExpr = getReconstructedExpression(projAttribStr, context);
this.substituteExpression(newExpr, i);
mappedColumn = true;
break;
}
}
}
}
return mappedColumn;
}
static class ProjectionField extends AbstractCompiledValue {
@Immutable
private static final ProjectionField singleton = new ProjectionField();
private ProjectionField() {}
@Override
public Object evaluate(ExecutionContext context) throws FunctionDomainException,
TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
return context.getCurrentProjectionField();
}
@Override
public int getType() {
return FIELD;
}
public static ProjectionField getProjectionField() {
return singleton;
}
@Override
void setTypecast(ObjectType objectType) {
throw new UnsupportedOperationException("Cannot modify singleton ProjectionField");
}
}
}