org.teiid.query.processor.relational.DependentAccessNode Maven / Gradle / Ivy
/*
* Copyright Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags and
* the COPYRIGHT.txt file distributed with this work.
*
* 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.
*/
package org.teiid.query.processor.relational;
import java.util.Collections;
import org.teiid.common.buffer.BlockedException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.util.Assertion;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.lang.QueryCommand;
/**
* Takes a query with 1 or more dependent sets from 1 or more sources and creates a series of commands. Dependent sets from the
* same source are treated as a special case. If there are multiple batches from that source, we will create replacement criteria
* in lock step - rather than forming the full cartesian product space. This implementation assumes that ordering will be
* respected above the access node and that the incoming dependent tuple values are already sorted.
*/
public class DependentAccessNode extends AccessNode {
//plan state
private int maxSetSize;
private int maxPredicates;
private boolean pushdown;
//processing state
private DependentCriteriaProcessor criteriaProcessor;
private Criteria dependentCrit;
private boolean sort = true;
/**
* Cached rewritten command to be used as the base for all dependent queries.
*/
private Command rewrittenCommand;
private boolean useBindings;
private boolean complexQuery;
public DependentAccessNode(int nodeID) {
super(nodeID);
}
/**
* @see org.teiid.query.processor.relational.AccessNode#close()
*/
public void closeDirect() {
super.closeDirect();
if (criteriaProcessor != null) {
criteriaProcessor.close();
}
}
public void reset() {
super.reset();
criteriaProcessor = null;
dependentCrit = null;
sort = true;
rewrittenCommand = null;
}
@Override
protected Command nextCommand() throws TeiidProcessingException, TeiidComponentException {
if (rewrittenCommand == null) {
Command atomicCommand = super.nextCommand();
try {
rewriteAndEvaluate(atomicCommand, getEvaluator(Collections.emptyMap()), this.getContext(), this.getContext().getMetadata());
} catch (BlockedException e) {
//we must decline already as the parent will assume open, and it will
//be too late
if (sort && ((Query)atomicCommand).getOrderBy() != null) {
declineSort();
}
throw e;
}
rewrittenCommand = atomicCommand;
nextCommand = null;
}
if (nextCommand == null && rewrittenCommand != null) {
nextCommand = (Command)rewrittenCommand.clone();
}
return super.nextCommand();
}
public Object clone() {
DependentAccessNode clonedNode = new DependentAccessNode(super.getID());
clonedNode.maxSetSize = this.maxSetSize;
clonedNode.maxPredicates = this.maxPredicates;
clonedNode.pushdown = this.pushdown;
clonedNode.useBindings = this.useBindings;
clonedNode.complexQuery = this.complexQuery;
super.copyTo(clonedNode);
return clonedNode;
}
/**
* @return Returns the maxSize.
*/
public int getMaxSetSize() {
return this.maxSetSize;
}
public int getMaxPredicates() {
return maxPredicates;
}
public void setMaxPredicates(int maxPredicates) {
this.maxPredicates = maxPredicates;
}
/**
* @param maxSize
* The maxSize to set.
*/
public void setMaxSetSize(int maxSize) {
this.maxSetSize = maxSize;
}
/**
* @see org.teiid.query.processor.relational.AccessNode#prepareNextCommand(org.teiid.query.sql.lang.Command)
*/
protected boolean prepareNextCommand(Command atomicCommand) throws TeiidComponentException, TeiidProcessingException {
Assertion.assertTrue(atomicCommand instanceof Query);
Query query = (Query)atomicCommand;
try {
if (this.criteriaProcessor == null) {
this.criteriaProcessor = new DependentCriteriaProcessor(this.maxSetSize, this.maxPredicates, this, query.getCriteria());
this.criteriaProcessor.setPushdown(pushdown);
this.criteriaProcessor.setUseBindings(useBindings);
this.criteriaProcessor.setComplexQuery(complexQuery);
}
if (this.dependentCrit == null) {
dependentCrit = criteriaProcessor.prepareCriteria();
}
query.setCriteria(dependentCrit);
} catch (BlockedException be) {
throw new AssertionError("Should not block prior to declining the sort"); //$NON-NLS-1$
//TODO: the logic could proactively decline the sort rather than throwing an exception
}
//walk up the tree and notify the parent join it is responsible for the sort
if (sort && query.getOrderBy() != null && criteriaProcessor.hasNextCommand()) {
declineSort();
}
if (!sort) {
query.setOrderBy(null);
}
boolean result = RelationalNodeUtil.shouldExecute(atomicCommand, true);
dependentCrit = null;
criteriaProcessor.consumedCriteria();
return result;
}
private void declineSort() {
RelationalNode parent = this.getParent();
RelationalNode child = this;
while (parent != null && !(parent instanceof JoinNode)) {
child = parent;
if (parent instanceof SortNode) {
return;
}
parent = parent.getParent();
}
if (parent != null) {
JoinNode joinNode = (JoinNode)parent;
if (joinNode.getJoinStrategy() instanceof MergeJoinStrategy) {
MergeJoinStrategy mjs = (MergeJoinStrategy)joinNode.getJoinStrategy();
if (joinNode.getChildren()[0] == child) {
mjs.setProcessingSortLeft(true);
} else {
mjs.setProcessingSortRight(true);
}
}
}
sort = false;
}
/**
* @see org.teiid.query.processor.relational.AccessNode#hasNextCommand()
*/
protected boolean hasNextCommand() {
return criteriaProcessor.hasNextCommand();
}
public void setPushdown(boolean pushdown) {
this.pushdown = pushdown;
}
@Override
public Boolean requiresTransaction(boolean transactionalReads) {
Boolean required = super.requiresTransaction(transactionalReads);
if (required != null) {
return required;
}
if (transactionalReads || !(this.getCommand() instanceof QueryCommand)) {
return true;
}
return null;
}
public boolean isUseBindings() {
return useBindings;
}
public void setUseBindings(boolean useBindings) {
this.useBindings = useBindings;
}
public void setComplexQuery(boolean complexQuery) {
this.complexQuery = complexQuery;
}
}