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

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

The newest version!
/*
 * 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.
 */

package com.gemstone.gemfire.cache.query.internal;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.query.AmbiguousNameException;
import com.gemstone.gemfire.cache.query.FunctionDomainException;
import com.gemstone.gemfire.cache.query.IndexType;
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.RegionNotFoundException;
import com.gemstone.gemfire.cache.query.SelectResults;
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;
import com.gemstone.gemfire.cache.query.internal.index.IndexUtils;
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;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.pdx.internal.PdxString;

/**
 * Class Description
 *
 * @version     $Revision: 1.1 $
 * @author      ericz
 */


public class CompiledIn extends AbstractCompiledValue implements Indexable {
  private CompiledValue elm;
  private CompiledValue colln;
  
  public CompiledIn(CompiledValue elm, CompiledValue colln) {
    this.elm = elm;
    this.colln = colln;
  }
  
  @Override
  public List getChildren() {
    List list = new ArrayList();
    list.add(elm);
    list.add(colln);
    return list;
  }
  
  public int getType() {
    return LITERAL_in;
  }
  
  public Object evaluate(ExecutionContext context)
  throws FunctionDomainException, TypeMismatchException, NameResolutionException,
          QueryInvocationTargetException {
    Object evalElm = this.elm.evaluate(context);
    
    Object evalColln = this.colln.evaluate(context);
    if (evalColln == null || evalColln == QueryService.UNDEFINED) {
      return QueryService.UNDEFINED;
    }
    
    // handle each type of collection that we support
    if (evalColln instanceof Map) {
      evalColln = ((Map)evalColln).entrySet();
    }
    
    if (evalColln instanceof Collection) {
      Iterator iterator = ((Collection)evalColln).iterator();
      while (iterator.hasNext()) {
        Object evalObj = evalElm;
        Object collnObj = iterator.next();
        if (evalElm instanceof PdxString && collnObj instanceof String) {
          evalObj = ((PdxString) evalElm).toString();
        }
        if (TypeUtils.compare(evalObj, collnObj, OQLLexerTokenTypes.TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }
    
    if (!evalColln.getClass().isArray()) {
      throw new TypeMismatchException(LocalizedStrings.CompiledIn_OPERAND_OF_IN_CANNOT_BE_INTERPRETED_AS_A_COLLECTION_IS_INSTANCE_OF_0.toLocalizedString(evalColln.getClass().getName()));
    }
    if (evalColln instanceof Object[]) {
      Object[] a = (Object[])evalColln;
      for (int i = 0; i < a.length; i++) {
        if (TypeUtils.compare(evalElm, a[i], TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }

    // at this point if evalElm is NULL, then it's a type mismatch
    if (evalElm == null) {
      throw new TypeMismatchException(LocalizedStrings.CompiledIn_IN_OPERATOR_CHECK_FOR_NULL_IN_PRIMITIVE_ARRAY.toLocalizedString());
    }

    // handle each type of primitive array
    if (evalColln instanceof long[]) {
      long[] a = (long[])evalColln;
      for (int i = 0; i < a.length; i++) {
        Object e = Long.valueOf(a[i]);
        if (TypeUtils.compare(evalElm, e, TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }
    
    if (evalColln instanceof double[]) {
      double[] a = (double[])evalColln;
      for (int i = 0; i < a.length; i++) {
        Object e = Double.valueOf(a[i]);
        if (TypeUtils.compare(evalElm, e, TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }
    
    if (evalColln instanceof float[]) {
      float[] a = (float[])evalColln;
      for (int i = 0; i < a.length; i++) {
        Object e = new Float(a[i]);
        if (TypeUtils.compare(evalElm, e, TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }
    
    if (evalColln instanceof int[]) {
      int[] a = (int[])evalColln;
      for (int i = 0; i < a.length; i++) {
        Object e = Integer.valueOf(a[i]);
        if (TypeUtils.compare(evalElm, e, TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }
    
    if (evalColln instanceof short[]) {
      short[] a = (short[])evalColln;
      for (int i = 0; i < a.length; i++) {
        Object e = Short.valueOf(a[i]);
        if (TypeUtils.compare(evalElm, e, TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }
    
    if (evalColln instanceof char[]) {
      char[] a = (char[])evalColln;
      for (int i = 0; i < a.length; i++) {
        Object e = Character.valueOf(a[i]);
        if (TypeUtils.compare(evalElm, e, TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }
    
    if (evalColln instanceof byte[]) {
      byte[] a = (byte[])evalColln;
      for (int i = 0; i < a.length; i++) {
        Object e = Byte.valueOf(a[i]);
        if (TypeUtils.compare(evalElm, e, TOK_EQ).equals(Boolean.TRUE)) {
          return Boolean.TRUE;
        }
      }
      return Boolean.FALSE;
    }

    // must be a boolean[]
    boolean[] a = (boolean[]) evalColln;
    for (int i = 0; i < a.length; i++) {
      Object e = Boolean.valueOf(a[i]);
      if (TypeUtils.compare(evalElm, e, TOK_EQ).equals(Boolean.TRUE)) {
        return Boolean.TRUE;
      }
    }
    return Boolean.FALSE;
  }
  
  // Asif: If the size of aray is two this implies that it is
  // a relation ship index & so the key field will be null in both the indexes
  // as key is not a meaningful entity. The 0th element will refer to LHS
  // operand
  // and 1th element will refer to RHS operannd
  public IndexInfo[] getIndexInfo(ExecutionContext context)
      throws TypeMismatchException, AmbiguousNameException,
      NameResolutionException {
    IndexInfo[] indexInfo = privGetIndexInfo(context);
    if (indexInfo != null) {
      if (indexInfo == NO_INDEXES_IDENTIFIER) {
        return null;
      } else {
        return indexInfo;
      }
    }
    if (!IndexUtils.indexesEnabled)
      return null;
    // get the path and index key to try
    PathAndKey pAndK = getPathAndKey(context);
    IndexInfo newIndexInfo[] = null;
    if (pAndK != null) {
      CompiledValue path = pAndK._path;
      CompiledValue indexKey = pAndK._key;
      IndexData indexData = QueryUtils.getAvailableIndexIfAny(path, context,
          this.TOK_EQ);
      IndexProtocol index = null;
      if (indexData != null) {
        index = indexData.getIndex();
      }
      if (index != null && index.isValid()) {
        newIndexInfo = new IndexInfo[1];
        newIndexInfo[0] = new IndexInfo(indexKey, path, index, indexData
            .getMatchLevel(), indexData.getMapping(), this.TOK_EQ);
      }
    }
    if (newIndexInfo != null) {
      privSetIndexInfo(newIndexInfo, context);
    } else {
      privSetIndexInfo(NO_INDEXES_IDENTIFIER, context);
    }
    return newIndexInfo;
  }


  // _indexInfo is a transient field
  // if this is just faulted in then can be null
  private IndexInfo[] privGetIndexInfo(ExecutionContext context) {
    return (IndexInfo[]) context.cacheGet(this);
  }

  private void privSetIndexInfo(IndexInfo[] indexInfo, ExecutionContext context) {
    context.cachePut(this, indexInfo);
  }

  // Invariant: the receiver is dependent on the current iterator.
  protected PlanInfo protGetPlanInfo(ExecutionContext context)
      throws TypeMismatchException, AmbiguousNameException, NameResolutionException {
    PlanInfo result = new PlanInfo();
    IndexInfo[] indexInfo = getIndexInfo(context);
    if (indexInfo == null) return result;
    for (int i = 0; i < indexInfo.length; ++i) {
      result.indexes.add(indexInfo[i]._index);
    }
    result.evalAsFilter = true;
    String preferredCondn = (String)context.cacheGet(PREF_INDEX_COND);
    if(preferredCondn != null) {
      //This means that the system is having only one independent iterator so equi join is ruled out.
      // thus the first index is guaranteed to be on the condition which may match our preferred index
      if(indexInfo[0]._index.getCanonicalizedIndexedExpression().equals(preferredCondn) && 
          (indexInfo[0]._index.getType() == IndexType.FUNCTIONAL || indexInfo[0]._index.getType() == IndexType.HASH)) {
        result.isPreferred = true;
      }
    }
    return result;
  }

  public Set computeDependencies(ExecutionContext context)
  throws TypeMismatchException, AmbiguousNameException, NameResolutionException {
    context.addDependencies(this, this.elm.computeDependencies(context));
    return context.addDependencies(this, this.colln.computeDependencies(context));
  }
  
  /**
   * specialized optimization for doing a bulk get on a region.
   * @return a List of entries if optimization was performed, null if no match
   */
  List optimizeBulkGet(CompiledRegion cRgn, ExecutionContext context) 
  throws RegionNotFoundException, TypeMismatchException,
         NameResolutionException, FunctionDomainException, QueryInvocationTargetException {
    // check the elm to see if it's the key on a map entry
    boolean match = false;
    CompiledValue resolution = null;
    
    if (this.elm instanceof CompiledID) {
      String id = ((CompiledID)this.elm).getId();
      if (id.equals("key") || id.equals("getKey")){
        resolution = context.resolve(id);
        if (resolution instanceof CompiledPath) {
          resolution = ((CompiledPath)resolution).getReceiver();
        }
      }
    }
    else if (this.elm instanceof CompiledPath) {
      CompiledPath cPath = (CompiledPath)this.elm;
      if (cPath.getTailID().equals("key") || cPath.getTailID().equals("getKey")) {
        CompiledValue cVal = cPath.getReceiver();
        if (cVal instanceof CompiledID) { 
          resolution = context.resolve(((CompiledID)cVal).getId());
        }
      }
    }
    else if (this.elm instanceof CompiledOperation) {
      CompiledOperation cOp = (CompiledOperation)this.elm;
      if (cOp.getMethodName().equals("key") || cOp.getMethodName().equals("getKey")) {
        if (cOp.getReceiver(context) instanceof CompiledID) {
          resolution = context.resolve(((CompiledID)cOp.getReceiver(context)).getId());
        }
        else if (cOp.getReceiver(context) == null) {
          match = true; // implicit operation on the iterator
        }
      }
    }
    // only one possible iterator in this case, so it's a match if resolution
    // is a RuntimeIterator
    if (!match && !(resolution instanceof RuntimeIterator)) {
      return null;
    }
    
    // element matches; finally, check to make sure the collection expression
    // is independent of all iterators
    if (context.isDependentOnAnyIterator(this.colln)) {
      return null;
    }
    
    // evaluate the collection
    Object evalColln = this.colln.evaluate(context);
    if (evalColln == null || evalColln == QueryService.UNDEFINED) {
      return null;
    }
    
    // only handle an actual Collection or an Object[] for this optimization
    Collection colln = null;
    if (evalColln instanceof Collection) {
      colln = (Collection)evalColln;
    }
    if (evalColln instanceof Object[]) {
      colln = Arrays.asList((Object[])evalColln);
    }
    
    if (colln != null) {
      QRegion rgn = (QRegion)cRgn.evaluate(context);
      
      // only do this optimization if the region keys is larger than the
      // collection
      if (rgn.keySet().size() < colln.size()) {
        return null;
      }
      
      LogWriterI18n logger = rgn.getCache().getLoggerI18n();
      if (logger.fineEnabled()) {
        logger.fine("Executing BULK GET on keys " + colln + ", in region " + rgn);
      }
      List results = new ArrayList(colln.size());
      
      // now do the iteration over this collection
      for (Iterator itr = colln.iterator(); itr.hasNext(); ) {
        Object key = itr.next();
        Region.Entry entry = rgn.getEntry(key);
        if (entry != null) {
          // the region contains this key, so add the entry to the results
          results.add(entry);
        }
      }
      return results;
    }
    return null;
  }  

  /**
   * get the path to see if there's an index for, and also determine which
   * CompiledValue is the key while we're at it
   */
  private PathAndKey getPathAndKey(ExecutionContext context)
      throws TypeMismatchException, AmbiguousNameException {
    // RuntimeIterator lIter = context.findRuntimeIterator(_left);
    // RuntimeIterator rIter = context.findRuntimeIterator(_right);
    boolean isLeftDependent = context.isDependentOnCurrentScope(this.elm);
    boolean isRightDependent = context.isDependentOnCurrentScope(this.colln);
    if ( !isLeftDependent  || isRightDependent ) return null;
    CompiledValue indexKey;
    CompiledValue path;
    path = this.elm;
    indexKey = this.colln;
    //Asif Do not worry about the nature of the collection. As long as it
    //is not dependent on the current scope we should be fine
    
    return new PathAndKey(path, indexKey);
  }
  

  /**
   * Asif : Evaluates as a filter taking advantage of indexes if appropriate.
   * This function has a meaningful implementation only in CompiledComparison &
   * CompiledUndefined . It is unsupported in other classes. The additional
   * parameters which it takes are a boolean which is used to indicate whether
   * the index result set needs to be expanded to the top level or not. The
   * second is a CompiledValue representing the operands which are only iter
   * evaluatable. The CompiledValue passed will be null except if a
   * GroupJunction has only one filter evaluatable condition & rest are iter
   * operands. In such cases , the iter operands will be evaluated while
   * expanding/cutting down the index resultset
   * 
   * @return SelectResults
   */
  public SelectResults filterEvaluate(ExecutionContext context,
      SelectResults intermediateResults, boolean completeExpansionNeeded,
      CompiledValue iterOperands, RuntimeIterator[] indpndntItrs, boolean isIntersection, boolean conditioningNeeded, boolean evalProj)
      throws FunctionDomainException, TypeMismatchException,
      NameResolutionException, QueryInvocationTargetException
  {
    // see if we're dependent on the current iterator
    // if not let super handle it
    // RuntimeIterator itr = context.getCurrentIterator();
    // Support.Assert(itr != null);
    if (!isDependentOnCurrentScope(context))
      return super.filterEvaluate(context, intermediateResults);
    IndexInfo[] idxInfo = getIndexInfo(context);
    Support
        .Assert(
            idxInfo != null,
            "a comparison that is dependent, not indexed, and filter evaluated is not possible");
    Support.Assert(idxInfo.length == 1,
        "In operator should have only one index");

    return singleBaseCollectionFilterEvaluate(context, intermediateResults,
        completeExpansionNeeded, iterOperands, idxInfo[0], indpndntItrs, isIntersection,conditioningNeeded,evalProj);

  }
  
  public int getOperator() {
    return TOK_EQ;
  }

  /** **************** PRIVATE METHODS ************************** 
   * @throws QueryInvocationTargetException 
   * @throws NameResolutionException 
   * @throws FunctionDomainException 
   * @throws TypeMismatchException */
  
  private void queryIndex(Object key,
                          IndexInfo indexInfo,
                          SelectResults results,
                          CompiledValue iterOperands,
                          RuntimeIterator[] indpndntItrs,
                          ExecutionContext context,
                          List projAttrib,
                          boolean conditioningNeeded)
  throws TypeMismatchException,
         FunctionDomainException,
         NameResolutionException,
         QueryInvocationTargetException {
    
    assert indexInfo != null;
    assert indexInfo._index != null;
 
    // Get new IndexInfo to put in context as we dont want it to evaluate
    // key collection again if its a CompiledSelect (Nested Query).
    IndexInfo contextIndexInfo = new IndexInfo(new CompiledLiteral(key),
        indexInfo._path(), indexInfo._getIndex(), 0, null,
        indexInfo._operator());
    context.cachePut(CompiledValue.INDEX_INFO, contextIndexInfo);
    indexInfo._index.query(key,
                             TOK_EQ,
                             results,
                             !conditioningNeeded ? iterOperands : null,
                             indpndntItrs == null ? null : indpndntItrs[0],
                             context,
                             projAttrib,
                             null,
                             false); // is Intersection    

                  
    
   
  }
  /**
   * evaluate as a filter, involving a single iterator. Use an index if
   * possible.
   */
  // Invariant: the receiver is dependent on the current iterator.
  private SelectResults singleBaseCollectionFilterEvaluate(
      ExecutionContext context, SelectResults intermediateResults,
      boolean completeExpansionNeeded, CompiledValue iterOperands,
      IndexInfo indexInfo, RuntimeIterator[] indpndntItr, boolean isIntersection, boolean conditioningNeeded, boolean evalProj)
      throws TypeMismatchException, AmbiguousNameException,
      FunctionDomainException, NameResolutionException,
      QueryInvocationTargetException
  {
    ObjectType resultType = indexInfo._index.getResultSetType();
    int indexFieldsSize = -1;
    SelectResults results = null;
    if (resultType instanceof StructType) {
      indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
    }
    else {
      indexFieldsSize = 1;      
    }    
    boolean useLinkedSet = false;      
    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; 
    }
    
    List projAttrib = null;
    // ////////////////////////////////////////////////////////////////
    ObjectType projResultType = null;
    if (!conditioningNeeded) {
      projResultType = evalProj ? (ObjectType)context
          .cacheGet(RESULT_TYPE) : null;
      if (projResultType != null) {
        resultType = projResultType;
        context.cachePut(RESULT_TYPE, Boolean.TRUE);
        projAttrib = (List)context.cacheGet(PROJ_ATTRIB);
      }
      if (isIntersection) {
        if (resultType instanceof StructType) {
          context.getCache().getLogger().fine(
              "StructType resultType.class=" + resultType.getClass().getName());
          if(useLinkedSet) {
            results = new LinkedStructSet((StructTypeImpl)resultType);
          }else {
            results = new StructBag((StructTypeImpl)resultType,
              context.getCachePerfStats());
          }
          indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
        }
        else {
          context.getCache().getLogger().fine(
              "non-StructType resultType.class="
                  + resultType.getClass().getName());
          if (useLinkedSet) {
            results = new LinkedResultSet(resultType);
          } else {
            results = new ResultsBag(resultType, context.getCachePerfStats());
          }
          indexFieldsSize = 1;
        }
      }
      else {
        if (intermediateResults != null && !completeExpansionNeeded) {
          results = intermediateResults;
        }
        else {
          if (resultType instanceof StructType) {
            context.getCache().getLogger().fine(
                "StructType resultType.class="
                    + resultType.getClass().getName());
            if (useLinkedSet) {
              results = new LinkedStructSet((StructTypeImpl)resultType);
            } else {
              results = (SelectResults)new StructBag((StructTypeImpl)resultType,
              context.getCachePerfStats());
            }
            indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
          }
          else {
            context.getCache().getLogger().fine(
                "non-StructType resultType.class="
                    + resultType.getClass().getName());
            if (useLinkedSet) {
              results = new LinkedResultSet(resultType);
            } else {
              results = new ResultsBag(resultType, context.getCachePerfStats());
            }
            indexFieldsSize = 1;
          }
        }
      }

    }else {
      if (resultType instanceof StructType) {
        context.getCache().getLogger().fine(
            "StructType resultType.class=" + resultType.getClass().getName());
        if (useLinkedSet) {
          results = new LinkedStructSet((StructTypeImpl)resultType);
        } else {
          results = new StructBag((StructTypeImpl)resultType,
            context.getCachePerfStats());
        }
        indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
      }
      else {
        context.getCache().getLogger().fine(
            "non-StructType resultType.class="
                + resultType.getClass().getName());
        if (useLinkedSet) {
          results = new LinkedResultSet(resultType);
        } else {
          results = new ResultsBag(resultType, context.getCachePerfStats());
        }
        indexFieldsSize = 1;
      }
    }
    
    
    QueryObserver observer = QueryObserverHolder.getInstance();
    try {
      Object evalColln = this.colln.evaluate(context);
      observer.beforeIndexLookup(indexInfo._index, TOK_EQ, evalColln);      
      //We need to reset the result type just in case the colln turned out to 
      //be a compiled comparison which could change the result type
      //Exec caches are incorrectly shared across all queries, this would result
      //in overriding the result type.  Once the result type was overridden
      //multiple projections and class cast exceptions could result due to
      //unexpected values overwriting expected values
      if (!conditioningNeeded) {
        if (projResultType != null) {
          resultType = projResultType;
          context.cachePut(RESULT_TYPE, Boolean.TRUE);
        }
      }
      // handle each type of collection that we support
      if (evalColln instanceof Map) {
        Iterator itr = ((Map)evalColln).entrySet().iterator();
        while (itr.hasNext()) {
          this.queryIndex(itr.next(),indexInfo, results,iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);          
        }

      }
      else if (evalColln instanceof Collection) {
        //Removing duplicates from the collection
        HashSet set = new HashSet((Collection)evalColln);
        Iterator itr = set.iterator();
        while (itr.hasNext()) {
          this.queryIndex(itr.next(),indexInfo, results,iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
        }

      }
      else {
        if (!evalColln.getClass().isArray()) {
          throw new TypeMismatchException(
              "Operand of IN cannot be interpreted as a Collection. "
                  + "Is instance of " + evalColln.getClass().getName());
        }
        if (evalColln instanceof Object[]) {
          Object[] arr = (Object[])evalColln;
          for (int i = 0; i < arr.length; ++i) {
            this.queryIndex(arr[i],indexInfo,results, iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
          }

        }
        else if (evalColln instanceof long[]) {
          long[] a = (long[])evalColln;
          for (int i = 0; i < a.length; i++) {            
            this.queryIndex(Long.valueOf(a[i]),indexInfo,results, iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
          }

        }
        else if (evalColln instanceof double[]) {
          double[] a = (double[])evalColln;
          for (int i = 0; i < a.length; i++) {
            this.queryIndex(Double.valueOf(a[i]),indexInfo,results, iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
          }

        }
        else if (evalColln instanceof float[]) {
          float[] a = (float[])evalColln;
          for (int i = 0; i < a.length; i++) {
            this.queryIndex(new Float(a[i]),indexInfo, results, iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
          }

        }
        else if (evalColln instanceof int[]) {
          int[] a = (int[])evalColln;
          for (int i = 0; i < a.length; i++) {
            this.queryIndex(Integer.valueOf(a[i]),indexInfo, results, iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
          }
        }
        else if (evalColln instanceof short[]) {
          short[] a = (short[])evalColln;
          for (int i = 0; i < a.length; i++) {
            this.queryIndex(Short.valueOf(a[i]),indexInfo, results, iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
          }

        }
        else if (evalColln instanceof char[]) {
          char[] a = (char[])evalColln;
          for (int i = 0; i < a.length; i++) {
            this.queryIndex(Character.valueOf(a[i]),indexInfo,results,iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
          }

        }
        else if (evalColln instanceof byte[]) {
          byte[] a = (byte[])evalColln;
          for (int i = 0; i < a.length; i++) {
            this.queryIndex(Byte.valueOf(a[i]),indexInfo,results, iterOperands, indpndntItr, context, projAttrib,conditioningNeeded);
          }

        }
        else {
          throw new TypeMismatchException(
              "Operand of IN cannot be interpreted as a Comparable Object. Operand is of type ="
                  + evalColln.getClass());

        }
      }
      
      if(conditioningNeeded) {
        results =  QueryUtils.getconditionedIndexResults(results, indexInfo,
            context, indexFieldsSize, completeExpansionNeeded,
            iterOperands, indpndntItr);        
      }else {       
        if(isIntersection && intermediateResults != null) {
          results = QueryUtils.intersection(intermediateResults, results, context);
        }
      }
      return results;
    }
    finally {
      observer.afterIndexLookup(results);
    }

  }

  public boolean isProjectionEvaluationAPossibility(ExecutionContext context)
  {
    return true;
  }
  
  @Override
  public boolean isLimitApplicableAtIndexLevel(ExecutionContext context)  {
    return true;
  }
  
  @Override
  public boolean isOrderByApplicableAtIndexLevel(ExecutionContext context,
      String canonicalizedOrderByClause) throws FunctionDomainException,
      TypeMismatchException, NameResolutionException,
      QueryInvocationTargetException {   
    return false;
  }
  public boolean isConditioningNeededForIndex(RuntimeIterator independentIter, 
      ExecutionContext context, boolean completeExpnsNeeded) throws AmbiguousNameException, TypeMismatchException, NameResolutionException  {
    IndexConditioningHelper ich = null;
    IndexInfo[] idxInfo = getIndexInfo(context);
    assert idxInfo.length == 1;
    int indexFieldsSize = -1;
    boolean conditioningNeeded = true;
    ObjectType indexRsltType = idxInfo[0]._index.getResultSetType();
    if (indexRsltType instanceof StructType) {
      indexFieldsSize = ((StructTypeImpl)indexRsltType).getFieldNames().length;
    }
    else {
      indexFieldsSize = 1;      
    }
    
    if (independentIter != null   && indexFieldsSize == 1) {
      ich = new IndexConditioningHelper(idxInfo[0], context, indexFieldsSize,
          completeExpnsNeeded, null, independentIter);
    }
    conditioningNeeded = ich == null || ich.shufflingNeeded;
    return conditioningNeeded;

  }
  

  /**
   * evaluate as a filter, producing an intermediate result set. This may
   * require iteration if there is no index available. Asif :The booelan true
   * implies that CompiledComparsion when existing on its own always requires a
   * Completeexpansion to top level iterators. This flag can get toggled to
   * false only from inside a GroupJunction
   * 
   * @param intermediateResults
   *          if this parameter is provided, and we have to iterate, then
   *          iterate over this result set instead of the entire base
   *          collection.
   */
  public SelectResults filterEvaluate(ExecutionContext context,
      SelectResults intermediateResults) throws FunctionDomainException,
      TypeMismatchException, NameResolutionException,
      QueryInvocationTargetException {
    // Asif : This function can be invoked only if the where clause contains
    // a single condition which is CompiledComparison.
    // If a CompiledComparison exists inside a GroupJunction, then it will
    // always
    // call the overloaded filterEvalauate with the RuntimeIterator passed
    // as not null.
    // Thus if the RuntimeIterator array passed is null then it is
    // guaranteed
    // that the condition was a isolatory condition ( directly in where
    // clause)
    // and the final iterators to which we need to expand to is all the
    // iterators
    // of the scope
    // Asif: hack for customer
    RuntimeIterator indpndntItr = null;
    List currentScopeIndpndntItrs = context.getAllIndependentIteratorsOfCurrentScope();
    Set rntmItrs =  QueryUtils.getCurrentScopeUltimateRuntimeIteratorsIfAny(this,context);
    if(rntmItrs.size() ==1 && currentScopeIndpndntItrs.size() == 1 ) {
      indpndntItr = (RuntimeIterator)rntmItrs.iterator().next();
    }
    
    return filterEvaluate(context, intermediateResults, true/*
                                                             * Complete
                                                             * Expansion needed
                                                             */, null, indpndntItr !=null?new RuntimeIterator[]{indpndntItr}:null/*
                    * Asif :It is safe to pass null as the independent iterator
                    * to which the condition belongs is required only if boolean
                    * complete expansion turns out to be false, which can happen
                    * only in case of CompiledComparison/CompiledUndefined
                    * called from roupJunction or CompositeGroupJunction
                    */,true /*is intersection*/,this.isConditioningNeededForIndex(indpndntItr, context, true), true);
  }

  /*
   * Asif : This function should never get invoked as now if a CompiledJunction
   * or GroupJunction contains a single filterable CompiledComparison it should
   * directly call filterEvaluate rather than auxFilterEvalutae. Overriding this
   * function just for ensuring that auxFilterEvaluate is not being called by
   * mistake.
   */
  public SelectResults auxFilterEvaluate(ExecutionContext context,
      SelectResults intermediateResults) throws FunctionDomainException,
      TypeMismatchException, NameResolutionException,
      QueryInvocationTargetException {
    Support
        .assertionFailed(" This auxFilterEvaluate of CompiledIn should never have got invoked.");
    return null;
  }
  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 thatSize = comparedTo.getSizeEstimate(context);
    int thatOperator = comparedTo.getOperator() ;    
    switch(thatOperator) {
        case TOK_EQ:
        case TOK_NE:
        case TOK_NE_ALT:
           isThisBetter = thisSize < thatSize;
           break;
        case LITERAL_and:
         //Asif: Give preference to IN . Is this right? It does not appear . Ideally we need to get
          //some estimate on Range. This case is possible only in case of RangeJunction
          break;
        case TOK_LE:
        case TOK_LT:
        case TOK_GE:
        case TOK_GT:
          //Give preference to this rather than that as this is more deterministic
          break;
        default :
            throw  new IllegalArgumentException("The operator type ="+ thatOperator + " is unknown");
    }          
      
    return isThisBetter;
  }
  public int getSizeEstimate(ExecutionContext context)throws FunctionDomainException, TypeMismatchException, NameResolutionException, QueryInvocationTargetException  {
    IndexInfo[] idxInfo = getIndexInfo(context);
    if (idxInfo == null) {
      // Asif: This implies it is an independent condition. So evaluate it first
      // in filter operand
      return 0;
    }
    assert idxInfo.length == 1;
    Object key = idxInfo[0].evaluateIndexKey(context);
    if (key != null && key.equals(QueryService.UNDEFINED))
      return 0;
    
    Object evalColln = this.colln.evaluate(context);
    
    int size = 0;
    // handle each type of collection that we support
    if (evalColln instanceof Map) {
      Iterator itr = ((Map)evalColln).entrySet().iterator();
      while (itr.hasNext()) {        
        size+=idxInfo[0]._index.getSizeEstimate(itr.next(), TOK_EQ, idxInfo[0]._matchLevel);                  
      }

    }
    else if (evalColln instanceof Collection) {
      Iterator itr = ((Collection)evalColln).iterator();
      while (itr.hasNext()) {
        size+=idxInfo[0]._index.getSizeEstimate(itr.next(), TOK_EQ, idxInfo[0]._matchLevel);
      }

    }
    else {
      if (!evalColln.getClass().isArray()) {
        throw new TypeMismatchException(
            "Operand of IN cannot be interpreted as a Collection. "
                + "Is instance of " + evalColln.getClass().getName());
      }
      if (evalColln instanceof Object[]) {
        Object[] arr = (Object[])evalColln;
        for (int i = 0; i < arr.length; ++i) {
          size+=idxInfo[0]._index.getSizeEstimate(arr[i], TOK_EQ, idxInfo[0]._matchLevel);
        }

      }
      else if (evalColln instanceof long[]) {
        long[] a = (long[])evalColln;
        for (int i = 0; i < a.length; i++) {         
          size+=idxInfo[0]._index.getSizeEstimate(Long.valueOf(a[i]), TOK_EQ, idxInfo[0]._matchLevel);
        }

      }
      else if (evalColln instanceof double[]) {
        double[] a = (double[])evalColln;
        for (int i = 0; i < a.length; i++) {          
          size+=idxInfo[0]._index.getSizeEstimate(Double.valueOf(a[i]), TOK_EQ, idxInfo[0]._matchLevel);          
        }

      }
      else if (evalColln instanceof float[]) {
        float[] a = (float[])evalColln;
        for (int i = 0; i < a.length; i++) {          
          size+=idxInfo[0]._index.getSizeEstimate(new Float(a[i]), TOK_EQ, idxInfo[0]._matchLevel);
          
        }

      }
      else if (evalColln instanceof int[]) {
        int[] a = (int[])evalColln;
        for (int i = 0; i < a.length; i++) {          
          size+=idxInfo[0]._index.getSizeEstimate(Integer.valueOf(a[i]), TOK_EQ, idxInfo[0]._matchLevel);
        }
      }
      else if (evalColln instanceof short[]) {
        short[] a = (short[])evalColln;
        for (int i = 0; i < a.length; i++) {          
          size+=idxInfo[0]._index.getSizeEstimate(Short.valueOf(a[i]), TOK_EQ, idxInfo[0]._matchLevel);
          
        }

      }
      else if (evalColln instanceof char[]) {
        char[] a = (char[])evalColln;
        for (int i = 0; i < a.length; i++) {          
          size+=idxInfo[0]._index.getSizeEstimate(Character.valueOf(a[i]), TOK_EQ, idxInfo[0]._matchLevel);
        }

      }
      else if (evalColln instanceof byte[]) {
        byte[] a = (byte[])evalColln;
        for (int i = 0; i < a.length; i++) {         
          size+=idxInfo[0]._index.getSizeEstimate(Byte.valueOf(a[i]), TOK_EQ, idxInfo[0]._matchLevel);
          
        }

      }
      else {
        throw new TypeMismatchException(
            "Operand of IN cannot be interpreted as a Comparable Object. Operand is of type ="
                + evalColln.getClass());

      }
    }
    return size;
    
  }


  /* Inner classes for passing stuff around */
  class PathAndKey {

    CompiledValue _path;
    CompiledValue _key;

    PathAndKey(CompiledValue path, CompiledValue indexKey) {
      _path = path;
      _key = indexKey;
    }
  }


  public boolean isRangeEvaluatable() {	
	return false;
  }
  
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy