Package org.teiid.query.tempdata

Source Code of org.teiid.query.tempdata.IndexInfo

/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.  Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/

package org.teiid.query.tempdata;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import org.teiid.common.buffer.TupleBrowser;
import org.teiid.common.buffer.TupleSource;
import org.teiid.core.TeiidComponentException;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.query.processor.CollectionTupleSource;
import org.teiid.query.processor.relational.RelationalNode;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.IsNullCriteria;
import org.teiid.query.sql.lang.MatchCriteria;
import org.teiid.query.sql.lang.OrderBy;
import org.teiid.query.sql.lang.OrderByItem;
import org.teiid.query.sql.lang.SetCriteria;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.sql.visitor.ElementCollectorVisitor;

/**
* Accumulates information about index usage.
*/
class IndexInfo {
 
  List<Object> lower = null;
  List<Object> upper = null;
  ArrayList<List<Object>> valueSet = new ArrayList<List<Object>>();
  TempTable table;
  Boolean ordering;
  boolean covering;
  TupleSource valueTs;
  List<Criteria> nonCoveredCriteria = new LinkedList<Criteria>();
  List<Criteria> coveredCriteria = new LinkedList<Criteria>();
 
  public IndexInfo(TempTable table, final List<? extends SingleElementSymbol> projectedCols, final Criteria condition, OrderBy orderBy, boolean primary) {
    this.table = table;
    if (primary || this.table.getColumnMap().keySet().containsAll(projectedCols)) {
      covering = true;
    }
    if (table.getPkLength() > 0) {
      processCriteria(condition, primary);
      if (orderBy != null && (covering || this.table.getColumnMap().keySet().containsAll(orderBy.getSortKeys()))) {
        ordering = useIndexForOrderBy(orderBy);
      }
    }
  }

  private void processCriteria(Criteria condition, boolean primary) {
    List<Criteria> crits = Criteria.separateCriteriaByAnd(condition);
    if (!primary) {
      for (Iterator<Criteria> critIter = crits.iterator(); critIter.hasNext();) {
        Criteria criteria = critIter.next();
        if (table.getColumnMap().keySet().containsAll(ElementCollectorVisitor.getElements(criteria, false))) {
          coveredCriteria.add(criteria);
        } else {
          covering = false;
          nonCoveredCriteria.add(criteria);
          critIter.remove();
        }
      }
    }
    for (int i = 0; i < table.getPkLength(); i++) {
      ElementSymbol keyColumn = table.getColumns().get(i);
      for (Iterator<Criteria> critIter = crits.iterator(); critIter.hasNext();) {
        Criteria criteria = critIter.next();
        if (criteria instanceof CompareCriteria) {
          CompareCriteria cc = (CompareCriteria)criteria;
          if (cc.getOperator() == CompareCriteria.NE
              || !(cc.getRightExpression() instanceof Constant)) {
            critIter.remove();
            continue;
          }
          if (!cc.getLeftExpression().equals(keyColumn)) {
            continue;
          }
          this.addCondition(i, (Constant)cc.getRightExpression(), cc.getOperator());
          critIter.remove();
        } else if (criteria instanceof IsNullCriteria) {
          IsNullCriteria inc = (IsNullCriteria)criteria;
          if (inc.isNegated() || !inc.getExpression().equals(keyColumn)) {
            continue;
          }
          this.addCondition(i, new Constant(null), CompareCriteria.EQ);
          critIter.remove();
        } else {
          if (i > 0) {
            critIter.remove();
            continue;
          }
          if (criteria instanceof MatchCriteria) {
            MatchCriteria matchCriteria = (MatchCriteria)criteria;
            if (matchCriteria.isNegated() || !matchCriteria.getLeftExpression().equals(keyColumn) || !(matchCriteria.getRightExpression() instanceof Constant)) {
              continue;
            }
            Constant value = (Constant)matchCriteria.getRightExpression();
            String pattern = (String)value.getValue();
            boolean escaped = false;
            StringBuilder prefix = new StringBuilder();
            for (int j = 0; i < pattern.length(); j++) {
                    char character = pattern.charAt(j);
                   
                    if (character == matchCriteria.getEscapeChar() && character != MatchCriteria.NULL_ESCAPE_CHAR) {
                        if (escaped) {
                            prefix.append(character);
                            escaped = false;
                        } else {
                            escaped = true;
                        }
                    } else if (character == MatchCriteria.WILDCARD_CHAR || character == MatchCriteria.MATCH_CHAR) {
                      break;
                    } else {
                      prefix.append(character);
                    }
            }
            if (prefix.length() > 0) {
              this.addCondition(i, new Constant(prefix.toString()), CompareCriteria.GE);
            }
          } else if (criteria instanceof SetCriteria) {
            SetCriteria setCriteria = (SetCriteria)criteria;
            if (!setCriteria.getExpression().equals(keyColumn) || !setCriteria.isAllConstants()) {
              continue;
            }
            Collection<Constant> values = (Collection<Constant>) setCriteria.getValues();
            this.addSet(i, values);
          }
        }
      }
    }
  }
 
  void addCondition(int i, Constant value, int comparisionMode) {
    switch (comparisionMode) {
    case CompareCriteria.EQ:
      if (i == 0) {
        valueSet.clear();
        valueSet.add(new ArrayList<Object>(table.getPkLength()));
      }
      if (valueSet.size() == 1) {
        valueSet.get(0).add(value.getValue());
      }
      lower = null;
      upper = null;
      break;
    case CompareCriteria.GE:
    case CompareCriteria.GT:
      if (valueSet.isEmpty()) {
        if (i == 0) {
          lower = new ArrayList<Object>(table.getPkLength());
          lower.add(value.getValue());
        } if (lower != null && lower.size() == i) {
          lower.add(value.getValue());
        }
      }
      break;
    case CompareCriteria.LE:
    case CompareCriteria.LT:
      if (valueSet.isEmpty()) {
        if (i == 0) {
          upper = new ArrayList<Object>(table.getPkLength());
          upper.add(value.getValue());
        } else if (upper != null && upper.size() == i) {
          upper.add(value.getValue());
        }
      }
      break;
    }
  }
 
  void addSet(int i, Collection<Constant> values) {
    if (!valueSet.isEmpty()) {
      return;
    }
    if (i == 0) {
      for (Constant constant : values) {
        List<Object> value = new ArrayList<Object>(table.getPkLength());
        value.add(constant.getValue());
        valueSet.add(value);
      }
      lower = null;
      upper = null;
    }
  }
 
  /**
   * Return a non-null direction if the index can be used, otherwise null.
   * @param orderBy
   * @return
   */
  private Boolean useIndexForOrderBy(OrderBy orderBy) {
    Boolean direction = null;
    int[] orderByIndexes = RelationalNode.getProjectionIndexes(this.table.getColumnMap(), orderBy.getSortKeys());
    for (int i = 0; i < table.getPkLength(); i++) {
      if (orderByIndexes.length <= i) {
        break;
      }
      if (orderByIndexes[i] != i) {
        return null;
      }
    }
    for (OrderByItem item : orderBy.getOrderByItems()) {
      if (item.getNullOrdering() != null) {
        return null;
      }
      if (item.isAscending()) {
        if (direction == null) {
          direction = OrderBy.ASC;
        } else if (direction != OrderBy.ASC) {
          return null;
        }
      } else if (direction == null) {
        direction = OrderBy.DESC;
      } else if (direction != OrderBy.DESC) {
        return null;
      }
    }
    return direction;
  }
 
  TupleBrowser createTupleBrowser() throws TeiidComponentException {
    boolean direction = OrderBy.ASC;
    if (ordering != null) {
      LogManager.logDetail(LogConstants.CTX_DQP, "Using index for ordering"); //$NON-NLS-1$
      direction = ordering;
    }
    if (valueTs != null) {
      LogManager.logDetail(LogConstants.CTX_DQP, "Using index value set"); //$NON-NLS-1$
      return new TupleBrowser(this.table.getTree(), valueTs, direction);
    }
    if (!valueSet.isEmpty()) {
      LogManager.logDetail(LogConstants.CTX_DQP, "Using index value set"); //$NON-NLS-1$
      CollectionTupleSource cts = null;
      if (direction == OrderBy.ASC) {
        cts = new CollectionTupleSource(valueSet.iterator());
      } else {
        cts = new CollectionTupleSource(new Iterator<List<Object>>() {
          ListIterator<List<Object>> iter = valueSet.listIterator(valueSet.size());
          @Override
          public boolean hasNext() {
            return iter.hasPrevious();
          }
          @Override
          public List<Object> next() {
            return iter.previous();
          }
          @Override
          public void remove() {
            throw new UnsupportedOperationException();
          }
        });
      }
      return new TupleBrowser(this.table.getTree(), cts, direction);
    }
    if (lower != null || upper != null) {
      LogManager.logDetail(LogConstants.CTX_DQP, "Using index for range query", lower, upper); //$NON-NLS-1$
    }
    return new TupleBrowser(this.table.getTree(), lower, upper, direction);
  }
 
}
TOP

Related Classes of org.teiid.query.tempdata.IndexInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.