Package org.teiid.query.processor.relational

Source Code of org.teiid.query.processor.relational.DependentCriteriaProcessor$SetState

/*
* 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.processor.relational;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.teiid.api.exception.query.ExpressionEvaluationException;
import org.teiid.common.buffer.BlockedException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.query.optimizer.relational.rules.NewCalculateCostUtil;
import org.teiid.query.processor.relational.SortUtility.Mode;
import org.teiid.query.rewriter.QueryRewriter;
import org.teiid.query.sql.lang.AbstractSetCriteria;
import org.teiid.query.sql.lang.CollectionValueIterator;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.CompoundCriteria;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.DependentSetCriteria;
import org.teiid.query.sql.lang.OrderBy;
import org.teiid.query.sql.lang.SetCriteria;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.util.ValueIterator;


public class DependentCriteriaProcessor {
 
    public static class SetState {

        Collection<Object> replacement = new LinkedHashSet<Object>();

        Expression valueExpression;

        ValueIterator valueIterator;

        Object nextValue;

        boolean isNull;
       
        float maxNdv = NewCalculateCostUtil.UNKNOWN_VALUE;
       
        boolean overMax;
    }

    class TupleState {

        private SortUtility sortUtility;
        private DependentValueSource dvs;
        private List<SetState> dependentSetStates = new LinkedList<SetState>();
        private String valueSource;

        public TupleState(String source) {
          this.valueSource = source;
        }

        public void sort() throws BlockedException,
                   TeiidComponentException, TeiidProcessingException {
            if (dvs == null) {
              //TODO: detect if we're already distinct
              if (sortUtility == null) {
                List<Expression> sortSymbols = new ArrayList<Expression>(dependentSetStates.size());
                  List<Boolean> sortDirection = new ArrayList<Boolean>(sortSymbols.size());
                  for (int i = 0; i < dependentSetStates.size(); i++) {
                      sortDirection.add(Boolean.valueOf(OrderBy.ASC));
                      sortSymbols.add(dependentSetStates.get(i).valueExpression);
                  }
                  DependentValueSource originalVs = (DependentValueSource)dependentNode.getContext().getVariableContext().getGlobalValue(valueSource);
                  this.sortUtility = new SortUtility(originalVs.getTupleBuffer().createIndexedTupleSource(), sortSymbols, sortDirection, Mode.DUP_REMOVE, dependentNode.getBufferManager(), dependentNode.getConnectionID(), originalVs.getTupleBuffer().getSchema());
              }
              dvs = new DependentValueSource(sortUtility.sort());
              for (SetState setState : dependentSetStates) {
                    setState.valueIterator = dvs.getValueIterator(setState.valueExpression);
                    if (setState.maxNdv > 0 && setState.maxNdv < dvs.getTupleBuffer().getRowCount()) {
                      ValueIterator vi = dvs.getValueIterator(setState.valueExpression);
                      Comparable last = null;
                      int distinctCount = 0;
                      while (vi.hasNext()) {
                        Comparable next = (Comparable) vi.next();
                        if (last == null || next.compareTo(last) != 0) {
                          distinctCount++;
                        }
                        last = next;
                      }
                      if (distinctCount > setState.maxNdv) {
                        setState.overMax = true;
                      }
                    }
          }
            }
        }
       
        public void close() {
            if (dvs != null) {
              sortUtility = null;
                dvs.getTupleBuffer().remove();
                dvs = null;
            }
        }
               
        public List<SetState> getDepedentSetStates() {
            return dependentSetStates;
        }
       
    }
   
    private static final int SORT = 2;
    private static final int SET_PROCESSING = 3;

    //constructor state
    private int maxSetSize;
    private int maxPredicates;
    private RelationalNode dependentNode;
    private Criteria dependentCrit;

    //initialization state
    private List<Criteria> queryCriteria;
    private Map<Integer, SetState> setStates = new HashMap<Integer, SetState>();
    private LinkedHashMap<String, TupleState> dependentState = new LinkedHashMap<String, TupleState>();
    private List<List<SetState>> sources = new ArrayList<List<SetState>>();

    // processing state
    private int phase = SORT;
    private LinkedList<Integer> restartIndexes = new LinkedList<Integer>();
    private int currentIndex;
    private boolean hasNextCommand;
    protected SubqueryAwareEvaluator eval;

    public DependentCriteriaProcessor(int maxSetSize, int maxPredicates, RelationalNode dependentNode, Criteria dependentCriteria) throws ExpressionEvaluationException, TeiidComponentException {
        this.maxSetSize = maxSetSize;
        this.maxPredicates = maxPredicates;
        this.dependentNode = dependentNode;
        this.dependentCrit = dependentCriteria;
        this.eval = new SubqueryAwareEvaluator(Collections.emptyMap(), dependentNode.getDataManager(), dependentNode.getContext(), dependentNode.getBufferManager());
        queryCriteria = Criteria.separateCriteriaByAnd(dependentCrit);
       
        for (int i = 0; i < queryCriteria.size(); i++) {
          Criteria criteria = queryCriteria.get(i);
            if (!(criteria instanceof AbstractSetCriteria)) {
                continue;
            }
           
            if (criteria instanceof SetCriteria) {
                SetCriteria setCriteria = (SetCriteria)criteria;
                if (setCriteria.isNegated() || setCriteria.getNumberOfValues() <= maxSetSize) {
                    continue;
                }
                SetState state = new SetState();
                setStates.put(i, state);
                LinkedHashSet<Object> values = new LinkedHashSet<Object>();
                for (Expression expr : (Collection<Expression>)setCriteria.getValues()) {
          values.add(eval.evaluate(expr, null));
        }
                state.valueIterator = new CollectionValueIterator(values);
                sources.add(Arrays.asList(state));
            } else if (criteria instanceof DependentSetCriteria) {
              DependentSetCriteria dsc = (DependentSetCriteria)criteria;
                String source = dsc.getContextSymbol();
               
                SetState state = new SetState();
                setStates.put(i, state);
                state.valueExpression = dsc.getValueExpression();
                TupleState ts = dependentState.get(source);
                if (ts == null) {
                  ts = new TupleState(source);
                  dependentState.put(source, ts);
                    sources.add(ts.getDepedentSetStates());
                }
                ts.getDepedentSetStates().add(state);
                state.maxNdv = dsc.getMaxNdv();
            }
        }       
    }

    public void close() {
        if (dependentState != null) {
            for (TupleState state : dependentState.values()) {
        state.close();
      }
        }
        if (this.eval != null) {
          this.eval.close();
        }
    }

    public Criteria prepareCriteria() throws TeiidComponentException, TeiidProcessingException {

        if (phase == SORT) {
          for (TupleState state : dependentState.values()) {
                state.sort();
            }

            phase = SET_PROCESSING;
        }

        replaceDependentValueIterators();
       
        LinkedList<Criteria> crits = new LinkedList<Criteria>();
       
        for (int i = 0; i < queryCriteria.size(); i++) {
          SetState state = this.setStates.get(i);
          if (state == null) {
            crits.add((Criteria)queryCriteria.get(i).clone());
          } else {
            Criteria crit = replaceDependentCriteria((AbstractSetCriteria)queryCriteria.get(i), state);
            if (crit == QueryRewriter.FALSE_CRITERIA) {
              return QueryRewriter.FALSE_CRITERIA;
            }
            crits.add(crit);
          }
        }
       
        if (crits.size() == 1) {
          return crits.get(0);
        }
        return new CompoundCriteria(CompoundCriteria.AND, crits);
    }
   
    public void consumedCriteria() {
        // flush only the value iterators starting at the restart index
        // it is only safe to do this after the super call to prepare command
        if (restartIndexes.isEmpty()) {
            return;
        }
       
        int restartIndex = restartIndexes.removeLast().intValue();
       
        for (int i = restartIndex; i < sources.size(); i++) {

            List<SetState> source = sources.get(i);

            for (SetState setState : source) {
              setState.replacement.clear();
            }
        }

        currentIndex = restartIndex;
    }

    /**
     * Replace the dependentSet value iterators with the next set of values from the independent tuple source
     *
     * @param dependentSets
     * @param replacementValueIterators
     * @throws TeiidComponentException
     */
    private void replaceDependentValueIterators() throws TeiidComponentException {
      int totalPredicates = sources.size();
      if (this.maxPredicates > 0) {
          //We have a bin packing problem if totalPredicates < sources - We'll address that case later.
        //TODO: better handling for the correlated composite case
        totalPredicates = Math.max(totalPredicates, this.maxPredicates);
      }
      long maxSize = Integer.MAX_VALUE;
      if (this.maxSetSize > 0) {
        maxSize = this.maxSetSize;
      }
      int currentPredicates = 0;
      for (int run = 0; currentPredicates < totalPredicates; run++) {
        currentPredicates = 0;
        if (!restartIndexes.isEmpty()) {
          currentIndex = restartIndexes.removeLast().intValue();
        }
          for (int i = 0; i < sources.size(); i++) {

              List<SetState> source = sources.get(i);

            if (i == currentIndex++) {
   
                int doneCount = 0;
   
                while (doneCount < source.size()) {
   
                    boolean isNull = false;
                    boolean lessThanMax = true;
   
                    for (SetState state : source) {
                      if (state.overMax) {
                        doneCount++;
                        continue;
                      }
                        if (state.nextValue == null && !state.isNull) {
                            if (state.valueIterator.hasNext()) {
                                state.nextValue = state.valueIterator.next();
                                state.isNull = state.nextValue == null;
                            } else {
                                state.valueIterator.reset();
                                doneCount++; // should be true for each iterator from this source
                                continue;
                            }
                        }
   
                        isNull |= state.isNull;
                        lessThanMax &= state.replacement.size() < maxSize * (run + 1);
                    }
   
                    if (doneCount == source.size()) {
                        if (!restartIndexes.isEmpty() && restartIndexes.getLast().intValue() == i) {
                            restartIndexes.removeLast();
                        }
                        break;
                    }
   
                    if (lessThanMax || isNull) {
                      for (SetState state : source) {
                            if (!isNull) {
                                state.replacement.add(state.nextValue);
                            }
                            state.nextValue = null;
                            state.isNull = false;
                        }
                    } else {
                        restartIndexes.add(i);
                        break;
                    }
                }
            }
             
              for (SetState setState : source) {
                currentPredicates += setState.replacement.size()/maxSize+(setState.replacement.size()%maxSize!=0?1:0);
        }
          }
         
            if (restartIndexes.isEmpty()) {
              break;
            }
      }

        hasNextCommand = !restartIndexes.isEmpty();
    }

    protected boolean hasNextCommand() {
        return hasNextCommand;
    }
   
    public Criteria replaceDependentCriteria(AbstractSetCriteria crit, SetState state) {
      if (state.overMax) {
        return QueryRewriter.TRUE_CRITERIA;
      }
      if (state.replacement.isEmpty()) {
            // No values - return criteria that is always false
            return QueryRewriter.FALSE_CRITERIA;
      }
      int numberOfSets = 1;
      int maxSize = Integer.MAX_VALUE;
      if (this.maxSetSize > 0) {
        maxSize = this.maxSetSize;
        numberOfSets = state.replacement.size()/maxSize + (state.replacement.size()%maxSize!=0?1:0);
      }
      Iterator<Object> iter = state.replacement.iterator();
      ArrayList<Criteria> orCrits = new ArrayList<Criteria>(numberOfSets);
     
      for (int i = 0; i < numberOfSets; i++) {
        if (maxSize == 1 || i + 1 == state.replacement.size()) {
        orCrits.add(new CompareCriteria(crit.getExpression(), CompareCriteria.EQ, newConstant(iter.next())));           
      } else {
          List<Constant> vals = new ArrayList<Constant>(Math.min(state.replacement.size(), maxSize));
       
          for (int j = 0; j < maxSize && iter.hasNext(); j++) {
            Object val = iter.next();
                  vals.add(newConstant(val));
              }
             
              SetCriteria sc = new SetCriteria();
              sc.setExpression(crit.getExpression());
              sc.setValues(vals);
              orCrits.add(sc);
      }
      }
      if (orCrits.size() == 1) {
        return orCrits.get(0);
      }
      return new CompoundCriteria(CompoundCriteria.OR, orCrits);
    }
   
    private Constant newConstant(Object val) {
      Constant c = new Constant(val);
      c.setBindEligible(true);
      return c;
    }

}
TOP

Related Classes of org.teiid.query.processor.relational.DependentCriteriaProcessor$SetState

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.