Package org.teiid.dqp.internal.process.multisource

Source Code of org.teiid.dqp.internal.process.multisource.MultiSourcePlanToProcessConverter

/*
* 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.dqp.internal.process.multisource;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.api.exception.query.ExpressionEvaluationException;
import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.api.exception.query.QueryValidatorException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.id.IDGenerator;
import org.teiid.core.types.DataTypeManager;
import org.teiid.dqp.internal.process.DQPWorkContext;
import org.teiid.language.SQLConstants.NonReserved;
import org.teiid.query.QueryPlugin;
import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
import org.teiid.query.optimizer.relational.PlanToProcessConverter;
import org.teiid.query.optimizer.relational.plantree.PlanNode;
import org.teiid.query.processor.relational.AccessNode;
import org.teiid.query.processor.relational.GroupingNode;
import org.teiid.query.processor.relational.NullNode;
import org.teiid.query.processor.relational.ProjectIntoNode;
import org.teiid.query.processor.relational.ProjectNode;
import org.teiid.query.processor.relational.RelationalNode;
import org.teiid.query.processor.relational.RelationalNodeUtil;
import org.teiid.query.processor.relational.RelationalPlan;
import org.teiid.query.processor.relational.UnionAllNode;
import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.rewriter.QueryRewriter;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.Insert;
import org.teiid.query.sql.lang.SPParameter;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.query.sql.navigator.DeepPreOrderNavigator;
import org.teiid.query.sql.symbol.AggregateSymbol;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.ExpressionSymbol;
import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.util.CommandContext;


public class MultiSourcePlanToProcessConverter extends PlanToProcessConverter {
 
  private Set<String> multiSourceModels;
  private DQPWorkContext workContext;
 
  private boolean multiSource;
  private boolean update;
 
  public MultiSourcePlanToProcessConverter(QueryMetadataInterface metadata,
      IDGenerator idGenerator, AnalysisRecord analysisRecord,
      CapabilitiesFinder capFinder, Set<String> multiSourceModels,
      DQPWorkContext workContext, CommandContext context) {
    super(metadata, idGenerator, analysisRecord, capFinder);
    this.multiSourceModels = multiSourceModels;
    this.workContext = workContext;
  }
 
  @Override
  public synchronized RelationalPlan convert(PlanNode planNode)
      throws QueryPlannerException, TeiidComponentException {
      RelationalPlan result = null;
    try {
      result = super.convert(planNode);
      return result;
    } finally {
      if (result != null && update && multiSource) {
        result.setMultisourceUpdate(true);
      }
      update = false;
      multiSource = false;
    }
  }

  protected RelationalNode convertNode(PlanNode planNode) throws QueryPlannerException, TeiidComponentException {
    RelationalNode node = super.convertNode(planNode);
   
    if (node instanceof AccessNode) {
      try {
        return multiSourceModify((AccessNode)node);
      } catch (TeiidProcessingException e) {
        throw new QueryPlannerException(e, e.getMessage());
      }
    } else if (node instanceof ProjectIntoNode) {
      throw new AssertionError("Multisource insert with query expression not allowed not allowed, should have been caught in validation."); //$NON-NLS-1$
    }
   
    return node;
  }
 
  private RelationalNode multiSourceModify(AccessNode accessNode) throws TeiidComponentException, TeiidProcessingException {
        String modelName = accessNode.getModelName();

    if(!this.multiSourceModels.contains(modelName)) {
            return accessNode;
        }
       
    VDBMetaData vdb = workContext.getVDB();
        ModelMetaData model = vdb.getModel(modelName);
        List<AccessNode> accessNodes = new ArrayList<AccessNode>();
       
        boolean hasOutParams = false;
        if (accessNode.getCommand() instanceof StoredProcedure) {
          StoredProcedure sp = (StoredProcedure)accessNode.getCommand();
          hasOutParams = sp.returnParameters() && sp.getProjectedSymbols().size() > sp.getResultSetColumns().size();
        }
       
        for(String sourceName:model.getSourceNames()) {
           
            // Create a new cloned version of the access node and set it's model name to be the bindingUUID
            AccessNode instanceNode = (AccessNode) accessNode.clone();
            instanceNode.setID(getID());
            instanceNode.setConnectorBindingId(sourceName);
           
            // Modify the command to pull the instance column and evaluate the criteria
            Command command = (Command)instanceNode.getCommand().clone();
           
            command = rewriteCommand(sourceName, command);
           
            if (command == null) {
              continue;
            }

            // Rewrite the command now that criteria may have been simplified
            try {
                command = QueryRewriter.rewrite(command, metadata, null);                   
                instanceNode.setCommand(command);
            } catch(QueryValidatorException e) {
                // ignore and use original command
            }
           
            if (!RelationalNodeUtil.shouldExecute(command, false)) {
                continue;
            }
                               
            accessNodes.add(instanceNode);
        }
       
        if (hasOutParams && accessNodes.size() != 1) {
          throw new QueryPlannerException(QueryPlugin.Util.getString("MultiSource.out_procedure", accessNode.getCommand())); //$NON-NLS-1$
        }

        switch(accessNodes.size()) {
            case 0:
            {
                if (RelationalNodeUtil.isUpdate(accessNode.getCommand())) {
                  //should return a 0 update count
                  ProjectNode pnode = new ProjectNode(getID());
                  pnode.setElements(accessNode.getElements());
                  pnode.setSelectSymbols(Arrays.asList(new ExpressionSymbol("x", new Constant(0)))); //$NON-NLS-1$
                  return pnode;
                }
                // Replace existing access node with a NullNode
                NullNode nullNode = new NullNode(getID());
                nullNode.setElements(accessNode.getElements());
                return nullNode;        
            }
            case 1:
            {
                // Replace existing access node with new access node (simplified command)
                AccessNode newNode = accessNodes.get(0);
                return newNode;                                               
            }
            default:
            {
              multiSource = true;
              UnionAllNode unionNode = new UnionAllNode(getID());
              unionNode.setElements(accessNode.getElements());
               
                for (AccessNode newNode : accessNodes) {
                  unionNode.addChild(newNode);
                }
             
              RelationalNode parent = unionNode;
             
                // More than 1 access node - replace with a union
              if (RelationalNodeUtil.isUpdate(accessNode.getCommand())) {
                update = true;
                GroupingNode groupNode = new GroupingNode(getID());                   
                AggregateSymbol sumCount = new AggregateSymbol("SumCount", NonReserved.SUM, false, (Expression)accessNode.getElements().get(0)); //$NON-NLS-1$             
                List<Expression> outputElements = new ArrayList<Expression>(1);               
                outputElements.add(sumCount);
                groupNode.setElements(outputElements);
                groupNode.addChild(unionNode);
               
                ProjectNode projectNode = new ProjectNode(getID());
               
                Expression intSum = ResolverUtil.getConversion(sumCount, DataTypeManager.getDataTypeName(sumCount.getType()), DataTypeManager.DefaultDataTypes.INTEGER, false, metadata.getFunctionLibrary());
               
                Expression rowCount = new ExpressionSymbol("RowCount", intSum); //$NON-NLS-1$               
                outputElements = new ArrayList<Expression>(1);               
                outputElements.add(rowCount);                
                projectNode.setElements(outputElements);
                projectNode.setSelectSymbols(outputElements);
                projectNode.addChild(groupNode);
               
                parent = projectNode;
              }
                return parent;
            }
        }
    }

  private Command rewriteCommand(String sourceName, Command command) throws ExpressionEvaluationException, TeiidComponentException {
    if (command instanceof StoredProcedure) {
      StoredProcedure obj = (StoredProcedure)command;
      for (Iterator<SPParameter> params = obj.getMapOfParameters().values().iterator(); params.hasNext();) {
        SPParameter param = params.next();
        if (param.getParameterType() != SPParameter.IN) {
          continue;
        }
        String shortName = SingleElementSymbol.getShortName(param.getName());       
          if(shortName.equalsIgnoreCase(MultiSourceElement.MULTI_SOURCE_ELEMENT_NAME)) {
              Constant source = (Constant)param.getExpression();
            params.remove();
            if (param.isUsingDefault() && source.isNull()) {
              continue;
            }
              if (!source.getValue().equals(sourceName)) {
                return null;
              }
            }
      }
    } if (command instanceof Insert) {
      Insert obj = (Insert)command;
      for (int i = 0; i < obj.getVariables().size(); i++) {
        ElementSymbol elem = obj.getVariables().get(i);
            Object metadataID = elem.getMetadataID();           
            if(metadataID instanceof MultiSourceElement) {
              Constant source = (Constant)obj.getValues().get(i);
            obj.getVariables().remove(i);
            obj.getValues().remove(i);
              if (!source.getValue().equals(sourceName)) {
                return null;
              }
            }
      }
    } else {
        // Replace all multi-source elements with the source name
        DeepPreOrderNavigator.doVisit(command, new MultiSourceElementReplacementVisitor(sourceName));
    }
   
    if (!RelationalNodeUtil.shouldExecute(command, false)) {
            return null;
        }
   
    return command;
  }

}
TOP

Related Classes of org.teiid.dqp.internal.process.multisource.MultiSourcePlanToProcessConverter

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.