blob: 398805af9883e5311c4fe9be456ffbe1aedcc889 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2005-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* more patents listed at http://www.pivotal.io/patents.
*========================================================================
*/
package com.gemstone.gemfire.cache.query.internal;
import java.util.*;
import com.gemstone.gemfire.GemFireCacheException;
import com.gemstone.gemfire.GemFireException;
import com.gemstone.gemfire.cache.CacheException;
import com.gemstone.gemfire.cache.query.AmbiguousNameException;
import com.gemstone.gemfire.cache.query.FunctionDomainException;
import com.gemstone.gemfire.cache.query.IndexInvalidException;
import com.gemstone.gemfire.cache.query.NameResolutionException;
import com.gemstone.gemfire.cache.query.QueryException;
import com.gemstone.gemfire.cache.query.QueryInvalidException;
import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
import com.gemstone.gemfire.cache.query.TypeMismatchException;
import com.gemstone.gemfire.cache.query.internal.parse.OQLLexerTokenTypes;
import com.gemstone.gemfire.cache.query.internal.types.TypeUtils;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
/**
* This class represents a compiled form of sort criterian present in order by
* clause
*
* @author Yogesh Mahajan
* @author Asif
*/
public class CompiledSortCriterion extends AbstractCompiledValue {
// Asif: criterion true indicates descending order
private boolean criterion = false;
private CompiledValue expr = null;
int columnIndex = -1;
// private String correctedCanonicalizedExpression = null;
private CompiledValue originalCorrectedExpression = null;
@Override
public List getChildren() {
return Collections.singletonList(this.originalCorrectedExpression);
}
/**
* @return int
*/
public int getType() {
return SORT_CRITERION;
}
/**
* evaluates sort criteria in order by clause
*
* @param context
* @return Object
* @throws FunctionDomainException
* @throws TypeMismatchException
* @throws NameResolutionException
* @throws QueryInvocationTargetException
*
* public Object evaluate(ExecutionContext context) throws
* FunctionDomainException, TypeMismatchException,
* NameResolutionException, QueryInvocationTargetException {
* if(this.columnIndex >= 0) { return
* context.getFieldFromProjectedRow(this.columnIndex); }else {
* return this.expr.evaluate(context); } }
*/
public Object evaluate(Object data, ExecutionContext context) {
Object value = null;
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) {
throw new CacheException(e) {
};
}
}
/**
* concstructor
*
* @param criterion
* @param cv
*/
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;
}
/*
* public String getCorrectedCanonicalizedExpression() { return
* this.correctedCanonicalizedExpression; }
*/
@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 AmbiguousNameException,
TypeMismatchException, NameResolutionException {
List<CompiledValue> expressions = PathUtils.collectCompiledValuesInThePath(
expr, context);
StringBuffer tempBuff = new StringBuffer();
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 CompiledOperation.METHOD_INV:
reconstruct.add(0, ((CompiledOperation) cv).getArguments());
reconstruct.add(0, ((CompiledOperation) cv).getMethodName());
break;
case CompiledPath.PATH:
reconstruct.add(0, ((CompiledPath) cv).getTailID());
break;
case CompiledIndexOperation.TOK_LBRACK:
reconstruct.add(0, ((CompiledIndexOperation) cv).getExpression());
break;
default:
throw new IllegalStateException(
"Unexpected CompiledValue in order by clause");
}
reconstruct.add(0, Integer.valueOf(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()).intValue();
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 AmbiguousNameException,
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
StringBuffer orderByExprBuffer = new StringBuffer(), projAttribBuffer = new StringBuffer();
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); */
StringBuffer temp = new StringBuffer();
rIter.generateCanonicalizedExpression(temp, context);
// this.correctedCanonicalizedExpression = temp.toString();
/* mappedColumn = true; */
String projAttribStr = temp.toString();
temp = new StringBuffer();
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 {
private static ProjectionField singleton = new ProjectionField();
private ProjectionField() {
}
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;
}
}
}