All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.cache.query.internal.RangeJunction Maven / Gradle / Ivy

/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed 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. See accompanying
 * LICENSE file.
 */
/*
 * Created on Jan 27, 2008
 */
package com.gemstone.gemfire.cache.query.internal;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.gemstone.gemfire.cache.query.AmbiguousNameException;
import com.gemstone.gemfire.cache.query.FunctionDomainException;
import com.gemstone.gemfire.cache.query.Index;
import com.gemstone.gemfire.cache.query.NameResolutionException;
import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
import com.gemstone.gemfire.cache.query.QueryService;
import com.gemstone.gemfire.cache.query.SelectResults;
import com.gemstone.gemfire.cache.query.TypeMismatchException;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
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.types.ObjectType;
import com.gemstone.gemfire.cache.query.types.StructType;

/**
 * This structure contains all the filter evaluatable CompiledComparision
 * conditions which are using identical index. Presently this Object will be
 * formed only if the junction is an AND and will either be a part of a
 * GroupJunction or can be a stand alone Junction. In case it is a stand alone
 * Junction, then it can possibly have a not null Iter Operand, so that it can
 * be evaluated along with the expansion/truncation of index result.
 * 
 * @author asif
 */
public class RangeJunction extends AbstractGroupOrRangeJunction {
  private final static int RANGE_SIZE_ESTIMATE = 3;
  //moved to AbstractGroupOrRangeJunction
  //private CompiledValue iterOperands;

  RangeJunction(int operator, RuntimeIterator[] indpndntItr,
      boolean isCompleteExpansion, CompiledValue[] operands) {
    super(operator, indpndntItr, isCompleteExpansion, operands);

  }
  void addUnevaluatedFilterOperands(List unevaluatedFilterOps) {
	throw new UnsupportedOperationException("This method should not have been invoked");  
  }
  // moved to AbstractGroupOrRangeJunction
/*  void addIterOperands(CompiledValue iterOps) {
    this.iterOperands = iterOps;
  }*/
  private RangeJunction(AbstractGroupOrRangeJunction oldGJ,
      boolean completeExpansion, RuntimeIterator indpnds[], CompiledValue iterOp) {
    super(oldGJ, completeExpansion, indpnds, iterOp);
  }

  @Override
  AbstractGroupOrRangeJunction recreateFromOld(boolean completeExpansion,
      RuntimeIterator indpnds[], CompiledValue iterOp) {
    return new RangeJunction(this, completeExpansion, indpnds, iterOp);
  }

  @Override
  AbstractGroupOrRangeJunction createNewOfSameType(int operator,
      RuntimeIterator[] indpndntItr, boolean isCompleteExpansion,
      CompiledValue[] operands) {
    return new RangeJunction(operator, indpndntItr, isCompleteExpansion,
        operands);
  }

  @Override
  public PlanInfo getPlanInfo(ExecutionContext context)
      throws FunctionDomainException, TypeMismatchException,
      NameResolutionException, QueryInvocationTargetException {
    /*
     * This function would be called only if the RangeJunction is a part of
     * GroupJunction.It would be invoked in the organized operands method of
     * GroupJunction. In such case it is guaranteed that all the operands are
     * the filter operand using the same index. In such case there is zero
     * possibility o first iterator being either an iter operand or a constant.
     * As those types of Operands would be part of Group Junction
     */
    return this._operands[0].getPlanInfo(context);
  }
  
  public boolean isConditioningNeededForIndex(RuntimeIterator independentIter, ExecutionContext context,  boolean completeExpnsNeeded) throws AmbiguousNameException, TypeMismatchException, NameResolutionException {
    return true;
  }
  
  public int getOperator() {
    return LITERAL_and;
  }
  
  public boolean isBetterFilter(Filter comparedTo, ExecutionContext context, final int thisSize) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException 
  {
    //If the current filter is equality & comparedTo filter is also equality based , then 
    // return the one with lower size estimate is better
    boolean isThisBetter = true;
   
    int thatOperator = comparedTo.getOperator() ;    
    switch(thatOperator) {
        case TOK_EQ:        
           isThisBetter = false;
           break;
        case TOK_NE:
        case TOK_NE_ALT:
          //Give preference to Range
          break;
        case LITERAL_and:
         //Asif: What to do? Let current be the better one for the want of better estimation
         break;
        case TOK_LE:
        case TOK_LT:
        case TOK_GE:
        case TOK_GT:
          //Give preference to this rather than single condition inequalities as a rangejunction
          //would possibly be bounded resulting in lesser values
          break;
        default :
            throw  new IllegalArgumentException("The operator type ="+ thatOperator + " is unknown");
    }          
      
    return isThisBetter;
  }

  /**
   * Segregates the operands of the RangeJunction into iter evaluatable and
   * filter evaluatable.
   */
  @Override
  OrganizedOperands organizeOperands(ExecutionContext context)
      throws FunctionDomainException, TypeMismatchException,
      NameResolutionException, QueryInvocationTargetException {
    // get the list of operands to evaluate,
    // and evaluate operands that can use indexes first
    if (getOperator() == LITERAL_and) {
      return organizeOperandsForAndJunction(context);
    }
    else {
      throw new IllegalStateException(
        LocalizedStrings.RangeJunction_IN_THE_CASE_OF_AN_OR_JUNCTION_A_RANGEJUNCTION_SHOULD_NOT_BE_FORMED_FOR_NOW.toLocalizedString());
    }
  }

  // TODO:Asif: Currently the condition a!= null AND a =3, would be evalauted
  // via intersection. This needs to be optmized, but since it is not
  // common use case as != null is a not required operand , for the time being
  // ignoring the optmization.
  /**
   * For the filter evaluatable conditions , it creates the appropriate
   * JunctionEvaluator ( NotEqualConditionEvaluator or SingleCondnEvaluator or
   * DoubleCondnRangeJunctionEvaluator ). The junction Evaluator itself is
   * filter evaluatable. The operands which are of type != null , == null , !=
   * undefined, == undefined are left as it is & are not combined into a
   * Junction Evaluator. Thus the organized operand of RangeJunction may created
   * atmost one Condition Evaluator, will retain the operands containing null
   * ,undefined conditions. In case there is a equality condition , then it may
   * result in a filter having just that condition assuming other conditions
   * satisfy the equality. In case it turns out that the conditions are mutually
   * exclusive then the organized operand would just contain a single filter
   * evaluatable CompiledLiteral (false) ( indicating empty resultset).
   */
  private OrganizedOperands organizeOperandsForAndJunction(
      ExecutionContext context) throws AmbiguousNameException,
      FunctionDomainException, TypeMismatchException, NameResolutionException,
      QueryInvocationTargetException {
    List evalOperands = new ArrayList(_operands.length);
    int evalCount = 0;
    int lessCondnOp = -1;
    int greaterCondnOp = -1;
    CompiledComparison lessCondnOperand = null;
    CompiledComparison greaterCondnOperand = null;
    CompiledComparison equalCondnOperand = null;
    Object equalCondKey = null;
    Object lessCondnKey = null;
    Object greaterCondnKey = null;
    boolean emptyResults = false;
    Set notEqualTypeKeys = null;
    boolean possibleRangeFilter = false;
    IndexInfo indxInfo = null;
    for (int i = 0; i < _operands.length; i++) {
      CompiledValue operand = _operands[i];
      if (operand.getPlanInfo(context).evalAsFilter) {
        Indexable cc = (Indexable)operand;
        if (indxInfo == null) {
          indxInfo = cc.getIndexInfo(context)[0];
        }
        // TODO: Asif :Try to ensure that a CompiledUndefined never
        // goes in the RangeJunction. That means modify the
        // CompiledJunction code to avoid CompiledUndefined's inclusion
        // That way we can ensure that CompiledComparison only become part
        // of RangeJunction
        if (!cc.isRangeEvaluatable()) {
          evalCount++;
          evalOperands.add(0, _operands[i]);
          continue;
        }
        CompiledValue ccKey = ((CompiledComparison)cc).getKey(context);
        Object evaluatedCCKey = ccKey.evaluate(context);
        int operator = ((CompiledComparison)cc).reflectOnOperator(ccKey);
        if (evaluatedCCKey == null) {
          evalCount++;
          evalOperands.add(0, _operands[i]);
          continue;
        }
        if (equalCondnOperand != null) {
          emptyResults = !isConditionSatisfied(equalCondKey, evaluatedCCKey,
              operator);
          if (emptyResults) {
            break;
          }
          else {
            continue;
          }
        }

        switch (operator) {
        case TOK_EQ:
          possibleRangeFilter = false;
          equalCondnOperand = (CompiledComparison)cc;
          equalCondKey = evaluatedCCKey;
          break;
        case TOK_NE:
        case TOK_NE_ALT:
          possibleRangeFilter = true;
          if (notEqualTypeKeys == null) {
            notEqualTypeKeys = new HashSet(_operands.length);
          }
          evaluatedCCKey = TypeUtils.indexKeyFor(evaluatedCCKey);
          notEqualTypeKeys.add(evaluatedCCKey);
          break;
        case TOK_GE:
        case TOK_GT:
          possibleRangeFilter = true;
          if (greaterCondnOperand == null) {
            greaterCondnOperand = (CompiledComparison)cc;
            greaterCondnKey = evaluatedCCKey;
            greaterCondnOp = operator;
          }
          else {
            if (isConditionSatisfied(evaluatedCCKey, greaterCondnKey,
                greaterCondnOp)) {
              greaterCondnKey = evaluatedCCKey;
              greaterCondnOperand = (CompiledComparison)cc;
              greaterCondnOp = operator;
            }
          }
          break;
        case TOK_LE:
        case TOK_LT:
          // Asif: if there exists a previous equal Operand & current
          // condition's value is greater than the equal operand's value, it
          // will be empty results
          possibleRangeFilter = true;
          if (lessCondnOperand == null) {
            lessCondnOperand = (CompiledComparison)cc;
            lessCondnKey = evaluatedCCKey;
            lessCondnOp = operator;
          }
          else {
            if (isConditionSatisfied(evaluatedCCKey, lessCondnKey, lessCondnOp)) {
              lessCondnKey = evaluatedCCKey;
              lessCondnOperand = (CompiledComparison)cc;
              lessCondnOp = operator;
            }
          }
          break;
        }

      }
      else if (!_operands[i].isDependentOnCurrentScope(context)) {
        // TODO: Asif :Remove this Assert & else if condition after successful
        // testing of the build
        Support
            .assertionFailed("An independentoperand should not ever be present as operand inside a GroupJunction as it should always be present only in CompiledJunction");
      }
      else {
        evalOperands.add(_operands[i]);
      }
    }
    if (!emptyResults) {
      Filter filter = null;
      if (equalCondnOperand != null) {
        // Check if any of the preceding inequality operands, that have not been
        // checked against the equality operand , are not able to satisfy the
        // equality.
        if (lessCondnOperand != null
            && !this.isConditionSatisfied(equalCondKey, lessCondnKey,
                lessCondnOp)) {
          emptyResults = true;
        }
        else if (greaterCondnOperand != null
            && !this.isConditionSatisfied(equalCondKey, greaterCondnKey,
                greaterCondnOp)) {
          emptyResults = true;
        }
        else if (notEqualTypeKeys != null) {
          Iterator itr = notEqualTypeKeys.iterator();
          while (itr.hasNext() && !emptyResults) {
            emptyResults = !this.isConditionSatisfied(equalCondKey, itr.next(),
                OQLLexerTokenTypes.TOK_NE);
          }
        }
        if (!emptyResults) {
          filter = equalCondnOperand;
        }
      }
      else if (possibleRangeFilter) {
        if (lessCondnOperand != null && greaterCondnOperand != null) {
          emptyResults = !checkForRangeBoundednessAndTrimNotEqualKeyset(
              notEqualTypeKeys, lessCondnKey, lessCondnOp, greaterCondnKey,
              greaterCondnOp);
          if (!emptyResults) {
            filter = new DoubleCondnRangeJunctionEvaluator(lessCondnOp,
                lessCondnKey, greaterCondnOp, greaterCondnKey,
                (notEqualTypeKeys == null || notEqualTypeKeys.isEmpty()) ? null
                    : notEqualTypeKeys, indxInfo);
          }
        }
        else if (greaterCondnOperand != null) {
          filter = generateSingleCondnEvaluatorIfRequired(notEqualTypeKeys,
              greaterCondnOperand, greaterCondnOp, greaterCondnKey, indxInfo);
        }
        else if (lessCondnOperand != null) {
          filter = generateSingleCondnEvaluatorIfRequired(notEqualTypeKeys,
              lessCondnOperand, lessCondnOp, lessCondnKey, indxInfo);
        }
        else {
          assert notEqualTypeKeys != null && !notEqualTypeKeys.isEmpty();
          // TODO:Asif Ideally if there is a single NotEqualKey we should
          // not create NotEqualCondnEvaluator instead just add the
          // CompiledComparison
          // operand to the eval operands list. But since we do retain the
          // operand
          // correponding to the NotEqualKey in this function , we are creating
          // the NotEqualCondnEvaluator
          filter = new NotEqualConditionEvaluator(notEqualTypeKeys, indxInfo);
        }

      }
      if (emptyResults) {
        evalOperands.clear();
        evalCount = 1;
        evalOperands.add(new CompiledLiteral(Boolean.FALSE));
      }
      else if (filter != null) {
        evalCount++;
        evalOperands.add(0, filter);
      }
    }
    else {
      // Asif: Create a new CompiledLiteral with boolean false
      evalOperands.clear();
      evalCount = 1;
      evalOperands.add(new CompiledLiteral(Boolean.FALSE));
    }
    
    // Asif: hack: At the end check if the unevaluatedIterOperand
    // are null or not. This could be the case only if at top level
    // GroupJunction is formed having multiple RangeJunctions & other
    // iter operands & then only one RangeJunction is treated as filter
    // rest all as iter operands. In that case , the only iter operand is
    // that which is added externally to RangeJunction. If the top
    // level was a RangeJunction then the iter operands would have been
    // part of it at the time of creation of RangeJunction & we would not have
    // to add it externally.
    if(getIterOperands() != null) {
      // Commented the assert for CompiledLike which creates 2 or 3 CompiledComparisons
      // for the same operand. The protGetPlanInfo in CompiledLike could return evalAsFilter 
      // as true the first time and false the next time for the same operand.
      // Hence the evalOperands could contain  CompiledComparisons more than number of indexes.
      
      //Support.Assert(evalOperands.size() == evalCount);
      evalOperands.add(getIterOperands());
    }
    return createOrganizedOperandsObject(evalCount, evalOperands);

  }

  /**
   * Checks if key1 operator key2 is true or not. The operator could be =, != , <, >,<=,>=
   * 
   * @param key1
   * @param key2
   * @param operator
   * @return boolean true if the condition is satisfied else false
   * @throws TypeMismatchException
   */
  private boolean isConditionSatisfied(Object key1, Object key2, int operator)
      throws TypeMismatchException {
    return ((Boolean)TypeUtils.compare(key1, key2, operator)).booleanValue();
  }

  /**
   * Checks if the Range junction containing less & greater type of inequalities
   * has a lower and upper bound , in the sense that they do not represent a
   * mutually exclusive condition like a> 10 and a <9 etc. If the condition is
   * bounded in nature, it further checks if the not equal type keys fall in the
   * bounded range , else it removes it from the Not Equal Keys set
   * 
   * @param notEqualKeys
   *                Set containing keys of operands having 'Not Equal' (!=) type
   *                conditions
   * @param lessCondnKey
   *                Key of the 'Less' condition operand
   * @param lessOperator
   *                Type of 'less' operator ( < or <=)
   * @param greaterCondnKey
   *                Key of the 'greater' condition operand
   * @param greaterCondnOp
   *                Type of 'greater' operator ( > or >=)
   * @return boolean true if the nature is bounded else false ( unbounded )
   * @throws TypeMismatchException
   */
  private boolean checkForRangeBoundednessAndTrimNotEqualKeyset(
      Set notEqualKeys, Object lessCondnKey, int lessOperator,
      Object greaterCondnKey, int greaterCondnOp) throws TypeMismatchException {
    // First check if the range is bounded or (unbounded and mutually
    // exclusive).
    // If it is unbounded immediately return a false
    if (isConditionSatisfied(greaterCondnKey, lessCondnKey, lessOperator)
        && isConditionSatisfied(lessCondnKey, greaterCondnKey, greaterCondnOp)) {
      // Nowremove those not equal conditions which do not satisfy the range
      if (notEqualKeys != null) {
        Iterator itr = notEqualKeys.iterator();
        Object neKey = null;
        while (itr.hasNext()) {
          neKey = itr.next();
          if (!this
              .isConditionSatisfied(neKey, greaterCondnKey, greaterCondnOp)
              || !this.isConditionSatisfied(neKey, lessCondnKey, lessOperator)) {
            itr.remove();
          }
        }
      }
      return true;
    }
    else {
      return false;
    }
  }

  /**
   * Creates a Filter of type SingleCondnEvaluator if there exists atleast one
   * key of type "NOT EQUAL" which satisfies the 'less' or 'greater' type
   * operand. Otherwise the Filter is nothing but the CompiledComparison
   * representing the 'less' or 'greater' inequality
   * 
   * @param notEqualKeys
   *                Set containing NotEqual type Keys
   * @param operand
   *                CompiledValue representing the 'Less' or 'Greater' operand
   * @param operator
   *                Type of 'Less' or 'Greater' operand
   * @param condnKey
   *                The Key corresponding to the Operand representing the 'Less'
   *                or 'Greater' inequality
   * @param indxInfo
   *                The IndexInfo object for this RangeJunction
   * @return Filter object of type CompiledComparison or
   *         RangeJunction.SingleCondnEvaluator object
   * @throws TypeMismatchException
   */
  private Filter generateSingleCondnEvaluatorIfRequired(Set notEqualKeys,
      CompiledValue operand, int operator, Object condnKey, IndexInfo indxInfo)
      throws TypeMismatchException {
    Filter rangeFilter;
    if (notEqualKeys != null) {
      // Eliminate all the not equal keys which will never be satisfied by
      // the given greater condn
      Iterator itr = notEqualKeys.iterator();
      while (itr.hasNext()) {
        Object neKey = itr.next();
        if (!((Boolean)TypeUtils.compare(neKey, condnKey, operator))
            .booleanValue()) {
          itr.remove();
        }
      }
      if (notEqualKeys.isEmpty()) {
        notEqualKeys = null;
      }
    }
    rangeFilter = (notEqualKeys != null) ? new SingleCondnEvaluator(operator,
        condnKey, notEqualKeys, indxInfo) : (Filter)operand;
    return rangeFilter;
  }

  public Object evaluate(ExecutionContext context)
  throws FunctionDomainException, TypeMismatchException,
  NameResolutionException, QueryInvocationTargetException {
    Object r = _operands[0].evaluate(context); // UNDEFINED, null, or a
    // Boolean

    // if it's false and the op in this case will always be AND so return
    // false immediately
    if (r instanceof Boolean && !((Boolean) r).booleanValue())
      return r;
    if (r == null || r == QueryService.UNDEFINED)
      r = QueryService.UNDEFINED; // keep going to see if we hit a
    // short-circuiting truth value
    else if (!(r instanceof Boolean))
      throw new TypeMismatchException(
          "LITERAL_and/LITERAL_or operands must be of type boolean, not type '"
          + r.getClass().getName() + "'");
    for (int i = 1; i < _operands.length; i++) {
      Object ri = _operands[i].evaluate(context); // UNDEFINED, null, or
      // Boolean
      if (ri instanceof Boolean && !((Boolean) ri).booleanValue())
        return ri;
      if (ri == null || ri == QueryService.UNDEFINED
          || r == QueryService.UNDEFINED) {
        r = QueryService.UNDEFINED;
        continue; // keep going to see if we hit a short-circuiting
        // truth value
      } else if (!(ri instanceof Boolean))
        throw new TypeMismatchException(
            "LITERAL_and/LITERAL_or operands must be of type boolean, not type '"
            + ri.getClass().getName() + "'");
      // now do the actual and

      r = Boolean.valueOf(((Boolean) r).booleanValue()
          && ((Boolean) ri).booleanValue());

    }
    return r;
  }

  @Override
  public int getType() {
    return LITERAL_and;
  }

  @Override
  public void visitNodes(NodeVisitor visitor) {
    Support.assertionFailed("Should not have come here");
  }

  public int getSizeEstimate(ExecutionContext context)
  {
    //TODO:Asif:Try to estimate better
     return RANGE_SIZE_ESTIMATE;
  }

  /*
   * private organizeOperandsForORJunction() {
   *  }
   */
  /**
   * Test method which checks if the Filter operand is of type
   * SingleCondnEvaluator
   */
  static boolean isInstanceOfSingleCondnEvaluator(Object o) {
    return o instanceof RangeJunction.SingleCondnEvaluator;
  }

  /**
   * Test method which checks if the Filter operand is of type
   * NotEqualConditionEvaluator
   */
  static boolean isInstanceOfNotEqualConditionEvaluator(Object o) {
    return o instanceof RangeJunction.NotEqualConditionEvaluator;
  }

  /**
   * Test method which checks if the Filter operand is of type
   * DoubleCondnRangeJunctionEvaluator
   */
  static boolean isInstanceOfDoubleCondnRangeJunctionEvaluator(Object o) {
    return o instanceof RangeJunction.DoubleCondnRangeJunctionEvaluator;
  }

  /**
   * Test function which retrieves the "NOT EQUAL KEYS"
   * 
   * @param o
   *                Object of type NotEqualConditionEvaluator from which the set
   *                containing the keys for removal need to be retrieved
   * @return Unmodifiable Set containing the keys for removal
   */
  static Set getKeysToBeRemoved(Object o) {
    if (o instanceof NotEqualConditionEvaluator) {
      if (((NotEqualConditionEvaluator)o).notEqualTypeKeys == null) {
        return null;
      }
      return Collections
          .unmodifiableSet(((NotEqualConditionEvaluator)o).notEqualTypeKeys);
    }
    else {
      throw new IllegalStateException(
          LocalizedStrings.
            RangeJunction_THE_OBJECT_IS_NOT_OF_TYPE_NOTEQUALCONDITIONEVALUATOR
            .toLocalizedString());
    }
  }

  /**
   * Test function which retrieves the SingleCondnEvaluator operator
   * 
   * @param o
   *                Object of type SingleCondnEvaluator from which the set
   *                containing the keys for removal need to be retrieved
   * @return int indicating the operator
   */
  static int getSingleCondnEvaluatorOperator(Object o) {
    if (o instanceof SingleCondnEvaluator) {
      return ((SingleCondnEvaluator)o).condnOp;
    }
    else {
      throw new IllegalStateException(
          LocalizedStrings.
            RangeJunction_THE_OBJECT_IS_NOT_OF_TYPE_NOTEQUALCONDITIONEVALUATOR
            .toLocalizedString());
    }
  }

  /**
   * Test function which retrieves the evaluated Key for a SingleCondnEvaluator
   * operator
   * 
   * @param o
   *                Object of type SingleCondnEvaluator from which the set
   *                containing the keys for removal need to be retrieved
   * @return Object representing the evaluated Key
   */
  static Object getSingleCondnEvaluatorKey(Object o) {
    if (o instanceof SingleCondnEvaluator) {
      return ((SingleCondnEvaluator)o).condnKey;
    }
    else {
      throw new IllegalStateException(
          LocalizedStrings.
            RangeJunction_THE_OBJECT_IS_NOT_OF_TYPE_NOTEQUALCONDITIONEVALUATOR
            .toLocalizedString());
    }
  }

  /**
   * Test function which retrieves the LESS type evaluated Key for a
   * DoubleCondnEvaluator operator
   * 
   * @param o
   *                Object of type DoubleCondnEvaluator
   * @return Object representing the evaluated Key of Less Type
   */
  static Object getDoubleCondnEvaluatorLESSKey(Object o) {
    if (o instanceof DoubleCondnRangeJunctionEvaluator) {
      return ((DoubleCondnRangeJunctionEvaluator)o).lessCondnKey;
    }
    else {
      throw new IllegalStateException(
          LocalizedStrings.
            RangeJunction_THE_OBJECT_IS_NOT_OF_TYPE_NOTEQUALCONDITIONEVALUATOR
            .toLocalizedString());
    }
  }

  /**
   * Test function which retrieves the GREATER type evaluated Key for a
   * DoubleCondnEvaluator operator
   * 
   * @param o
   *                Object of type DoubleCondnEvaluator
   * @return Object representing the evaluated Key of GREATER Type
   */
  static Object getDoubleCondnEvaluatorGreaterKey(Object o) {
    if (o instanceof DoubleCondnRangeJunctionEvaluator) {
      return ((DoubleCondnRangeJunctionEvaluator)o).greaterCondnKey;
    }
    else {
      throw new IllegalStateException(
          LocalizedStrings.
            RangeJunction_THE_OBJECT_IS_NOT_OF_TYPE_NOTEQUALCONDITIONEVALUATOR
            .toLocalizedString());
    }
  }

  /**
   * Test function which retrieves the operator of Less Type
   * 
   * @param o
   *                Object of type DoubleCondnEvaluator
   * @return int indicating the operator of less Type
   */
  static int getDoubleCondnEvaluatorOperatorOfLessType(Object o) {
    if (o instanceof DoubleCondnRangeJunctionEvaluator) {
      return ((DoubleCondnRangeJunctionEvaluator)o).lessCondnOp;
    }
    else {
      throw new IllegalStateException(
          LocalizedStrings.
            RangeJunction_THE_OBJECT_IS_NOT_OF_TYPE_NOTEQUALCONDITIONEVALUATOR
            .toLocalizedString());
    }
  }

  /**
   * Test function which retrieves the operator of GREATER Type
   * 
   * @param o
   *                Object of type DoubleCondnEvaluator
   * @return int indicating the operator of less Type
   */
  static int getDoubleCondnEvaluatorOperatorOfGreaterType(Object o) {
    if (o instanceof DoubleCondnRangeJunctionEvaluator) {
      return ((DoubleCondnRangeJunctionEvaluator)o).greaterCondnOp;
    }
    else {
      throw new IllegalStateException(
          LocalizedStrings.
            RangeJunction_THE_OBJECT_IS_NOT_OF_TYPE_NOTEQUALCONDITIONEVALUATOR
            .toLocalizedString());
    }
  }

  /**
   * Test function which retrieves the underlying Index for a
   * NotEqualConditionEvaluator operator
   * 
   * @param o
   *                Object of type NotEqualConditionEvaluator from which the
   *                index needs to be retrieved
   * @return Index
   */
  static Index getIndex(Object o) {
    if (o instanceof NotEqualConditionEvaluator) {
      return ((NotEqualConditionEvaluator)o).indxInfo._index;
    }
    else {
      throw new IllegalStateException(
          LocalizedStrings.
            RangeJunction_THE_OBJECT_IS_NOT_OF_TYPE_NOTEQUALCONDITIONEVALUATOR
            .toLocalizedString());
    }
  }

  /**
   * Filter Object created by the RangeJunction on invocation of its
   * organizedOperands method. The object of this class will be created only if
   * RangeJunction contains more than one 'NOT EQUAL' ( != ) type conditions (
   * apart from conditions having null or undefined as key). This class is also
   * extended by SingleCondnEvaluator and DoubleCondnRangeJunctionEvaluator
   * 
   * @author asif
   * 
   */
  private static class NotEqualConditionEvaluator extends AbstractCompiledValue
      implements Filter {
    final Set notEqualTypeKeys;

    final IndexInfo indxInfo;

    /**
     * 
     * @param notEqualTypeKeys
     *                java.utils.Set object containing the Keys of the 'NOT
     *                EQUAL' type conditions ( a != 3 and a !=5) For
     *                DoubleCondnRangeJunctionEvaluator , this may be null
     * @param indxInfo
     *                The IndexInfo object corresponding to the RangeJunction
     */
    NotEqualConditionEvaluator(Set notEqualTypeKeys, IndexInfo indxInfo) {
      this.notEqualTypeKeys = notEqualTypeKeys;
      this.indxInfo = indxInfo;
    }

    @Override
    public SelectResults filterEvaluate(ExecutionContext context,
        SelectResults iterationLimit) throws FunctionDomainException,
        TypeMismatchException, NameResolutionException,
        QueryInvocationTargetException {
      throw new UnsupportedOperationException();
    }

    @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 {
      ObjectType resultType = this.indxInfo._index.getResultSetType();
      int indexFieldsSize = -1;
      SelectResults set = null;
      Boolean orderByClause = (Boolean)context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
      boolean useLinkedSet = false;      
      if(orderByClause != null && orderByClause.booleanValue()) {
        List orderByAttrs = (List)context.cacheGet(CompiledValue.ORDERBY_ATTRIB);        
        useLinkedSet =orderByAttrs.size()==1; 
      }
      
      if (resultType instanceof StructType) {
        if (context.getCache().getLogger().fineEnabled()) {
          context.getCache().getLogger().fine(
            "StructType resultType.class=" + resultType.getClass().getName());
        }
        if (useLinkedSet) {
          set = new LinkedStructSet((StructTypeImpl)resultType) ;
        } else {
          set = (SelectResults)new StructBag((StructTypeImpl)resultType,
                                           context.getCachePerfStats());
        }
        indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
      }
      else {
        if (context.getCache().getLogger().fineEnabled()) {
          context.getCache().getLogger().fine(
            "non-StructType resultType.class="
                + resultType.getClass().getName());
        }
        if (useLinkedSet) {
          set = new LinkedResultSet(resultType); 
        } else {
          set = new ResultsBag(resultType, context.getCachePerfStats());
        }
        indexFieldsSize = 1;
      }
      // actual index lookup
      QueryObserver observer = QueryObserverHolder.getInstance();
      /*
       * Asif : First obtain the match level of index resultset. If the match
       * level happens to be zero , this implies that we just have to change the
       * StructType ( again if only the Index resultset is a StructBag). If the
       * match level is zero & expand to to top level flag is true & iff the
       * total no. of iterators in current scope is greater than the no. of
       * fields in StructBag , then only we need to do any expansion.
       * 
       */
      try {
        observer.beforeIndexLookup(this.indxInfo._index,
            OQLLexerTokenTypes.TOK_NE, this.notEqualTypeKeys);
        context.cachePut(CompiledValue.INDEX_INFO, this.indxInfo);
        this.indxInfo._index.query(set, notEqualTypeKeys, context);
      }
      finally {
        observer.afterIndexLookup(set);
      }
      return QueryUtils.getconditionedIndexResults(set, this.indxInfo, context,
          indexFieldsSize, completeExpansionNeeded, iterOperands, indpndntItrs);
    }

    @Override
    public SelectResults auxFilterEvaluate(ExecutionContext context,
        SelectResults intermediateResults) throws FunctionDomainException,
        TypeMismatchException, NameResolutionException,
        QueryInvocationTargetException {
      throw new UnsupportedOperationException();
    }

    public Object evaluate(ExecutionContext context) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
			Object evaluatedPath = this.indxInfo._path.evaluate(context); 
			return evaluate(context,evaluatedPath);
    }
    
    public boolean isConditioningNeededForIndex(RuntimeIterator independentIter, ExecutionContext context,  boolean completeExpnsNeeded) throws AmbiguousNameException, TypeMismatchException, NameResolutionException {
      return true;
    }

    public Object evaluate(ExecutionContext context, Object evaluatedPath) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {		 
		Iterator itr = this.notEqualTypeKeys.iterator();
		while(itr.hasNext()) {
			Object  val = itr.next();
			Object result = TypeUtils.compare(evaluatedPath, val, TOK_NE);
			if( result instanceof Boolean) {
			  if( !((Boolean)result).booleanValue()) {
				  return Boolean.FALSE;
			  }
			}else {
				throw new TypeMismatchException("NotEqualConditionEvaluator should evaluate to boolean type");
			}
		}
		return Boolean.TRUE;

    }

    public int getType() {
      return NOTEQUALCONDITIONEVALUATOR;
    }
    public int getSizeEstimate(ExecutionContext context) {
  	  return RANGE_SIZE_ESTIMATE;
    }
    @Override
    public void visitNodes(NodeVisitor visitor) {
      Support.assertionFailed("Should not have come here");
    }

    public int getOperator()
    {
      return LITERAL_and;
    }

    public boolean isBetterFilter(Filter comparedTo, ExecutionContext context, int thisSize) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException
    {
      //If the current filter is equality & comparedTo filter is also equality based , then 
      // return the one with lower size estimate is better
      boolean isThisBetter = true;
     
      int thatOperator = comparedTo.getOperator() ;    
      switch(thatOperator) {
          case TOK_EQ:        
             isThisBetter = false;
             break;
          case TOK_NE:
          case TOK_NE_ALT:
            //Give preference to Range
            break;        
          default :
              throw  new IllegalArgumentException("The operator type ="+ thatOperator + " is unknown");
      }          
        
      return isThisBetter;
    }

  }

  /**
   * Filter object of this type gets created if there exists atleast one "NOT
   * EQUAL" type condition and a single condition containing an inequality of
   * type 'Less' or 'Greater'. The Where clause may actually contain multiple
   * 'Less' type inequality or multiple 'Greater' type inequality ( though not
   * both 'Less' and 'Greater' together). The RangeJunction will identify the
   * most specific inequality for the AND junction. Thus if something like a > 7
   * and a >=6 , will be sufficiently represented by a > 7
   * 
   * @author asif
   * 
   */
  private static class SingleCondnEvaluator extends NotEqualConditionEvaluator {
    protected int condnOp = -1;

    protected final Object condnKey;

    @Override
    public SelectResults filterEvaluate(ExecutionContext context,
        SelectResults iterationLimit) throws FunctionDomainException,
        TypeMismatchException, NameResolutionException,
        QueryInvocationTargetException {
      throw new UnsupportedOperationException();
    }

    /**
     * 
     * @param operator
     *                integer identifying the type of 'Less' or 'Greater'
     *                inequality
     * @param key
     *                Object representing the Key for the inequality
     * @param notEqualKeys
     *                Set containing the 'NOT EQUAL' Keys accompanying the
     *                'Less' or 'Greater' inequality
     * @param indxInfo
     *                The IndexInfo object corresponding to the RangeJunction
     */
    SingleCondnEvaluator(int operator, Object key, Set notEqualKeys,
        IndexInfo indxInfo) {
      super(notEqualKeys, indxInfo);
      this.condnOp = operator;
      this.condnKey = key;
    }

    @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 {
      ObjectType resultType = this.indxInfo._index.getResultSetType();
      int indexFieldsSize = -1;
      SelectResults set = null;
      Boolean orderByClause = (Boolean)context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
      boolean useLinkedSet = false;      
      if(orderByClause != null && orderByClause.booleanValue()) {
        List orderByAttrs = (List)context.cacheGet(CompiledValue.ORDERBY_ATTRIB);        
        useLinkedSet =orderByAttrs.size()==1; 
      }
      if (resultType instanceof StructType) {
        if (context.getCache().getLogger().fineEnabled()) {
          context.getCache().getLogger().fine(
            "StructType resultType.class=" + resultType.getClass().getName());
        }
        if (useLinkedSet) {
          set = new LinkedStructSet((StructTypeImpl)resultType);
        } else {
          set = (SelectResults)new StructBag((StructTypeImpl)resultType,
              context.getCachePerfStats());
        }
        indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
      }
      else {
        if (context.getCache().getLogger().fineEnabled()) {
          context.getCache().getLogger().fine(
            "non-StructType resultType.class="
                + resultType.getClass().getName());
        }
        if (useLinkedSet) {
          set = new LinkedResultSet(resultType); 
        } else {
          set = new ResultsBag(resultType, context.getCachePerfStats());
        }
        indexFieldsSize = 1;
      }
      // actual index lookup
      QueryObserver observer = QueryObserverHolder.getInstance();
      /*
       * Asif : First obtain the match level of index resultset. If the match
       * level happens to be zero , this implies that we just have to change the
       * StructType ( again if only the Index resultset is a StructBag). If the
       * match level is zero & expand to to top level flag is true & iff the
       * total no. of iterators in current scope is greater than the no. of
       * fields in StructBag , then only we need to do any expansion.
       * 
       */
      try {
        observer.beforeIndexLookup(this.indxInfo._index, this.condnOp,
            this.condnKey);
        context.cachePut(CompiledValue.INDEX_INFO, this.indxInfo);
        this.indxInfo._index.query(this.condnKey, this.condnOp, set,
            notEqualTypeKeys, context);
      }
      finally {
        observer.afterIndexLookup(set);
      }
      return QueryUtils.getconditionedIndexResults(set, this.indxInfo, context,
          indexFieldsSize, completeExpansionNeeded, iterOperands, indpndntItrs);

    }

    public Object evaluate(ExecutionContext context) throws TypeMismatchException, FunctionDomainException, NameResolutionException, QueryInvocationTargetException {
      Object evaluatedPath = this.indxInfo._path.evaluate(context);
      Boolean result =(Boolean) super.evaluate(context,evaluatedPath);
      if( result.booleanValue()) {
    	  result = (Boolean)TypeUtils.compare(evaluatedPath, this.condnKey, this.condnOp);
      }
      return result;
    }

    @Override
    public int getType() {
      return SINGLECONDNEVALUATOR;
    }

    @Override
    public void visitNodes(NodeVisitor visitor) {
      Support.assertionFailed("Should not have come here");
    }
    
    @Override
    public SelectResults auxFilterEvaluate(ExecutionContext context,
        SelectResults intermediateResults) throws FunctionDomainException,
        TypeMismatchException, NameResolutionException,
        QueryInvocationTargetException {
      throw new UnsupportedOperationException();
    }
  }

  /**
   * Filter object of this type gets created if there exists a bounded condition
   * like a >7 and a > 8 and a< 10 and a <11. The RangeJunction will identify
   * the most specific inequality of each type for the AND junction. Thus the
   * conditions a > 8 and a <10 will be used to form the Object of this class.
   * For this evaluator only, the notEqualTypeKeys present in its super class
   * may be null ( if there is no 'NOT EQUAL' type condition satisfying the
   * bounded condition)
   * 
   * @author ashahid
   * 
   */
  private static class DoubleCondnRangeJunctionEvaluator extends
      NotEqualConditionEvaluator {
    protected final int lessCondnOp;

    protected final int greaterCondnOp;

    protected final Object lessCondnKey;

    protected final Object greaterCondnKey;

    /**
     * 
     * @param lessCondnOp
     *                integer identifying the upper bound ( < or <= )
     * @param lessCondnKey
     *                Object representing the Upper Bound Key
     * @param greaterCondnOp
     *                integer identifying the lower bound ( > or >= )
     * @param greaterCondnKey
     *                Object representing the lower Bound Key
     * @param notEqualTypeKeys
     *                Set containing the 'NOT EQUAL' Keys accompanying the
     *                'Less' or 'Greater' inequality
     * @param indexInfo
     *                The IndexInfo object corresponding to the RangeJunction
     */
    DoubleCondnRangeJunctionEvaluator(int lessCondnOp, Object lessCondnKey,
        int greaterCondnOp, Object greaterCondnKey, Set notEqualTypeKeys,
        IndexInfo indexInfo) {
      super(notEqualTypeKeys, indexInfo);
      this.lessCondnOp = lessCondnOp;
      this.lessCondnKey = lessCondnKey;
      this.greaterCondnOp = greaterCondnOp;
      this.greaterCondnKey = greaterCondnKey;
    }

    @Override
    public SelectResults filterEvaluate(ExecutionContext context,
        SelectResults iterationLimit) throws FunctionDomainException,
        TypeMismatchException, NameResolutionException,
        QueryInvocationTargetException {
      throw new UnsupportedOperationException();
    }

    @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 {
      ObjectType resultType = this.indxInfo._index.getResultSetType();
      int indexFieldsSize = -1;
      SelectResults set = null;
      Boolean orderByClause = (Boolean)context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
      boolean useLinkedSet = false;      
      if(orderByClause != null && orderByClause.booleanValue()) {
        List orderByAttrs = (List)context.cacheGet(CompiledValue.ORDERBY_ATTRIB);        
        useLinkedSet =orderByAttrs.size()==1; 
      }
      
      if (resultType instanceof StructType) {
        if (context.getCache().getLogger().fineEnabled()) {
          context.getCache().getLogger().fine(
            "StructType resultType.class=" + resultType.getClass().getName());
        }
        if(useLinkedSet) {
          set = new LinkedStructSet((StructTypeImpl)resultType);
        }else {
          set = new StructBag((StructTypeImpl)resultType,
                                           context.getCachePerfStats());
        }
        indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
      }
      else {
        if (context.getCache().getLogger().fineEnabled()) {
          context.getCache().getLogger().fine(
            "non-StructType resultType.class="
                + resultType.getClass().getName());
        }
        if (useLinkedSet) {
          set = new  LinkedResultSet(resultType); 
        } else {
          set = new ResultsBag(resultType, context.getCachePerfStats());
        }
        indexFieldsSize = 1;
      }
      // actual index lookup
      // Shobhit: Limit can not be applied at index level for RangeJunction as
      // other conditions are applied after coming out of index query method.
      context.cachePut(CompiledValue.CAN_APPLY_LIMIT_AT_INDEX, Boolean.FALSE);
      QueryObserver observer = QueryObserverHolder.getInstance();
      /*
       * Asif : First obtain the match level of index resultset. If the match
       * level happens to be zero , this implies that we just have to change the
       * StructType ( again if only the Index resultset is a StructBag). If the
       * match level is zero & expand to to top level flag is true & iff the
       * total no. of iterators in current scope is greater than the no. of
       * fields in StructBag , then only we need to do any expansion.
       * 
       */
      try {
        observer.beforeIndexLookup(this.indxInfo._index, this.greaterCondnOp,
            this.greaterCondnKey, this.lessCondnOp, this.lessCondnKey,
            this.notEqualTypeKeys);
        context.cachePut(CompiledValue.INDEX_INFO, this.indxInfo);
        this.indxInfo._index.query(this.greaterCondnKey, this.greaterCondnOp,
            this.lessCondnKey, this.lessCondnOp, set, notEqualTypeKeys, context);
      }
      finally {
        observer.afterIndexLookup(set);
      }
      return QueryUtils.getconditionedIndexResults(set, this.indxInfo, context,
          indexFieldsSize, completeExpansionNeeded, iterOperands, indpndntItrs);

    }

    @Override
    public SelectResults auxFilterEvaluate(ExecutionContext context,
        SelectResults intermediateResults) throws FunctionDomainException,
        TypeMismatchException, NameResolutionException,
        QueryInvocationTargetException {
      throw new UnsupportedOperationException();
    }

    public Object evaluate(ExecutionContext context) throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
        Object evaluatedPath = this.indxInfo._path.evaluate(context);
        Boolean result =(Boolean) super.evaluate(context,evaluatedPath);
        if( result.booleanValue()) {
      	  result = (Boolean)TypeUtils.compare(evaluatedPath, this.lessCondnKey, this.lessCondnOp);
      	  result = result.booleanValue() ? (Boolean)TypeUtils.compare(evaluatedPath, this.greaterCondnKey, this.greaterCondnOp):Boolean.FALSE;
        }
        return result;
    }

    @Override
    public int getType() {
      return DOUBLECONDNRANGEJUNCTIONEVALUATOR;
    }

    @Override
    public void visitNodes(NodeVisitor visitor) {
      Support.assertionFailed("Should not have come here");
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy