blob: 493c48d466eb8dc9db4fb3d5ca32b6e43a0869f1 [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.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.geode.cache.query.AmbiguousNameException;
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.QueryService;
import org.apache.geode.cache.query.SelectResults;
import org.apache.geode.cache.query.TypeMismatchException;
import org.apache.geode.cache.query.internal.parse.OQLLexerTokenTypes;
import org.apache.geode.cache.query.internal.types.StructTypeImpl;
import org.apache.geode.cache.query.types.ObjectType;
/**
* Class Description
*
* @version $Revision: 1.1 $
*/
public abstract class AbstractCompiledValue implements CompiledValue, Filter, OQLLexerTokenTypes {
ObjectType typecast = null;
@Override
public ObjectType getTypecast() {
return this.typecast;
}
// used for typecasts
void setTypecast(ObjectType objectType) {
this.typecast = objectType;
}
/** Default impl returns null as N/A */
@Override
public List getPathOnIterator(RuntimeIterator itr, ExecutionContext context)
throws TypeMismatchException, AmbiguousNameException {
return null;
}
/**
* Asif : This function has a meaningful implementaion only in CompiledComparison & Compiled
* Undefined
*/
@Override
public SelectResults filterEvaluate(ExecutionContext context, SelectResults iterationLimit,
boolean completeExpansionNeeded, CompiledValue iterOperands, RuntimeIterator[] indpndntItrs,
boolean isIntersection, boolean conditioningNeeded, boolean evalProj)
throws FunctionDomainException, TypeMismatchException, NameResolutionException,
QueryInvocationTargetException {
Support.assertionFailed(
"This method should not have invoked as CompieldComparison & CompiledUndefined are the only classes on which this invocation should have occurred ");
return null;
}
// determine whether should evaluate as filters, and what indexes will
// be used
// default is true for evalAsFilter if independent of iterator, otherwise
// calls protGetPlanInfo (which defaults to false for evalAsFilter)
@Override
public PlanInfo getPlanInfo(ExecutionContext context) throws FunctionDomainException,
TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
PlanInfo planInfo;
// RuntimeIterator itr = context.getCurrentIterator();
// Support.Assert(itr != null);
if (!isDependentOnCurrentScope(context)) {
// Asif :If the current junction or CompliedComparison
// happens to be independent , then its basic nature to be
// evaluatable as Filter depends upon its boolean value.
// If the operand is part of a Junction , then if it evaluates
// to false, it can always support filterEvaluatable. But if it
// evaluates to true, its nature is not to support filterEvaluatable
// The gist being that if an independent operand evaluates to
// false & if the junction is AND , the whole junction can be
// filter evaluatable. But if it evaluates to true, then by itself
// it cannot make junction filterEvaluatable, but if there exists
// any other operand which had an index or is independent ( with value
// as false), then the current operand can get AuxFilterEvaluated
// along with the other auxFilterEvaluatable operand.
// But if it is an OR junction , a true value would mean that the
// Junction cannot be evaluated as filter , but if it is false then
// junction can be evaluated as a filter , provided all the operands
// are also filterEvaluatable.
planInfo = new PlanInfo();
Object result = evaluate(context);
if (!(result instanceof Boolean))
throw new TypeMismatchException(
String.format("boolean value expected, not type ' %s '",
result.getClass().getName()));
boolean b = ((Boolean) result).booleanValue();
planInfo.evalAsFilter = !b;
return planInfo;
}
planInfo = protGetPlanInfo(context);
return planInfo;
}
@Override
public Set computeDependencies(ExecutionContext context)
throws TypeMismatchException, AmbiguousNameException, NameResolutionException {
// default implementation has no dependencies
// override in subclasses to add dependencies
return Collections.EMPTY_SET;
}
@Override
public boolean isDependentOnIterator(RuntimeIterator itr, ExecutionContext context) {
return context.isDependentOn(this, itr);
}
/**
* Return true if this value is dependent on any iterator in the current scope
*/
@Override
public boolean isDependentOnCurrentScope(ExecutionContext context) {
return context.isDependentOnCurrentScope(this);
}
// Invariant: the receiver is dependent on the current iterator.
protected PlanInfo protGetPlanInfo(ExecutionContext context) throws FunctionDomainException,
TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
return new PlanInfo(); // default behavior
}
// Utility methods
/**
* return operator used when terms are reversed, maintaining the semantics e.g salary < 100000
* swapped to 100000 > salary, salary >= 100000 swapped to 100000 <= salary or salary = 100000
* swapped to salary = 100000
*/
protected int reflectOperator(int op) {
switch (op) {
case TOK_EQ:
return TOK_EQ;
case TOK_NE:
return TOK_NE;
case TOK_LT:
return TOK_GT;
case TOK_GE:
return TOK_LE;
case TOK_LE:
return TOK_GE;
case TOK_GT:
return TOK_LT;
default:
Support.assertionFailed("unknown operator: " + op);
throw new Error("this line of code can never be executed");
}
}
/**
* return operator to invert the value of the result. e.g. salary < 100000 will become salary >=
* 100000 or salary = 100000 becomes salary != 100000
*/
protected int inverseOperator(int op) {
switch (op) {
case LITERAL_and:
return LITERAL_or;
case LITERAL_or:
return LITERAL_and;
case TOK_EQ:
return TOK_NE;
case TOK_NE:
return TOK_EQ;
case TOK_LT:
return TOK_GE;
case TOK_GE:
return TOK_LT;
case TOK_LE:
return TOK_GT;
case TOK_GT:
return TOK_LE;
default:
Support.assertionFailed("unknown operator: " + op);
throw new Error("this line of code can never be executed");
}
}
/**
* this is a lower level filter evaluation call. Most Filters do nothing different here than a
* normal filterEvaluate. This is here for benefit of nested CompiledJunctions: filterEvaluate is
* called first, then auxFilterEvaluate is called on the operands that have been organized to be
* filters
*
* @see CompiledJunction#filterEvaluate
*/
@Override
public SelectResults auxFilterEvaluate(ExecutionContext context,
SelectResults intermediateResults) throws FunctionDomainException, TypeMismatchException,
NameResolutionException, QueryInvocationTargetException {
return filterEvaluate(context, intermediateResults);
}
@Override
public SelectResults filterEvaluate(ExecutionContext context, SelectResults intermediateResults)
throws FunctionDomainException, TypeMismatchException, NameResolutionException,
QueryInvocationTargetException {
// for the general case of filter evaluation, most compiled values
// can only be evaluated in this way if they are independent of the current
// iterator,
// This method is also only applicable in places where a boolean value is
// expected.
// RuntimeIterator itr = context.getCurrentIterator();
// Support.Assert(itr != null);
// if it is possible for the following assertion to be false,
// then this method as well as protGetPlanInfo must be overridden
Support.Assert(!isDependentOnCurrentScope(context));
Object result = evaluate(context);
if (result == null || result == QueryService.UNDEFINED)
return new ResultsBag(intermediateResults.getCollectionType().getElementType(), 0,
context.getCachePerfStats());
if (!(result instanceof Boolean))
throw new TypeMismatchException(
String.format("boolean value expected, not type ' %s '",
result.getClass().getName()));
boolean b = ((Boolean) result).booleanValue();
// Asif : Boolean true, means the cartesian of all the RuntimeIterators
// indicated by null value. A false means an empty ResultSet
if (b) {
return null;
} else {
// Asif : We need to return either an empty ResultSet or an empty
// StructSet based
// on the number of iterators in the current scope.
SelectResults emptySet = null;
List iterators = context.getCurrentIterators();
int len = iterators.size();
if (len == 1) {
ObjectType elementType = ((RuntimeIterator) iterators.get(0)).getElementType();
emptySet = context.isDistinct() ? new ResultsSet(elementType)
: new ResultsBag(elementType, 0, context.getCachePerfStats());
} else {
String fieldNames[] = new String[len];
ObjectType fieldTypes[] = new ObjectType[len];
for (int i = 0; i < len; i++) {
RuntimeIterator iter = (RuntimeIterator) iterators.get(i);
fieldNames[i] = iter.getInternalId();
fieldTypes[i] = iter.getElementType();
}
emptySet = context.isDistinct() ? new StructSet(new StructTypeImpl(fieldNames, fieldTypes))
: new StructBag(0, new StructTypeImpl(fieldNames, fieldTypes),
context.getCachePerfStats());
}
return emptySet;
}
}
// This function needs to be appropriately overridden in the derived classes
@Override
public void generateCanonicalizedExpression(StringBuilder clauseBuffer, ExecutionContext context)
throws AmbiguousNameException, TypeMismatchException, NameResolutionException {
clauseBuffer.insert(0, System.currentTimeMillis());
clauseBuffer.insert(0, this.getClass());
clauseBuffer.insert(0, '.');
}
@Override
public void getRegionsInQuery(Set regionsInQuery, Object[] parameters) {
for (Iterator itr = getChildren().iterator(); itr.hasNext();) {
CompiledValue v = (CompiledValue) itr.next();
if (v == null) {
throw new NullPointerException(
String.format("Got null as a child from %s",
this));
}
v.getRegionsInQuery(regionsInQuery, parameters);
}
}
/** Get the CompiledValues that this owns */
@Override
public List getChildren() {
return Collections.EMPTY_LIST;
}
@Override
public int getSizeEstimate(ExecutionContext context) throws FunctionDomainException,
TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
throw new UnsupportedOperationException("This method should not have been invoked");
}
@Override
public void visitNodes(NodeVisitor visitor) {
visitor.visit(this);
for (Iterator itr = getChildren().iterator(); itr.hasNext();) {
if (!visitor.visit((CompiledValue) itr.next())) {
break;
}
}
}
@Override
public boolean isProjectionEvaluationAPossibility(ExecutionContext context)
throws FunctionDomainException, TypeMismatchException, NameResolutionException,
QueryInvocationTargetException {
throw new UnsupportedOperationException("This method should not have been invoked");
}
@Override
public boolean isLimitApplicableAtIndexLevel(ExecutionContext context)
throws FunctionDomainException, TypeMismatchException, NameResolutionException,
QueryInvocationTargetException {
throw new UnsupportedOperationException("This method should not have been invoked");
}
@Override
public boolean isOrderByApplicableAtIndexLevel(ExecutionContext context,
String canonicalizedOrderByClause) throws FunctionDomainException, TypeMismatchException,
NameResolutionException, QueryInvocationTargetException {
throw new UnsupportedOperationException("This method should not have been invoked");
}
@Override
public boolean isConditioningNeededForIndex(RuntimeIterator independentIter,
ExecutionContext context, boolean completeExpnsNeeded)
throws AmbiguousNameException, TypeMismatchException, NameResolutionException {
throw new UnsupportedOperationException("This method should not have been invoked");
}
@Override
public int getOperator() {
throw new UnsupportedOperationException("This method should not have been invoked");
}
@Override
public boolean isBetterFilter(Filter comparedTo, ExecutionContext context, int thisSize)
throws FunctionDomainException, TypeMismatchException, NameResolutionException,
QueryInvocationTargetException {
throw new UnsupportedOperationException("This method should not have been invoked");
}
@Override
public CompiledValue getReceiver() {
throw new UnsupportedOperationException("This method should not have been invoked");
}
}