/*
* 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 org.teiid.api.exception.query.ExpressionEvaluationException;
import org.teiid.core.TeiidComponentException;
import org.teiid.query.eval.Evaluator;
import org.teiid.query.sql.lang.*;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.visitor.EvaluatableVisitor;
/**
* @since 4.2
*/
public class RelationalNodeUtil {
private RelationalNodeUtil() {
}
/**
* Decides whether a command needs to be executed.
* <br/><b>NOTE: This method has a side-effect.</b> If the criteria of this command always evaluate to true,
* and the simplifyCriteria flag is true, then the command criteria are set to null.
* @param command
* @param simplifyCriteria whether to simplify the criteria of the command if they always evaluate to true
* @return true if this command should be executed by the connector; false otherwise.
* @throws TeiidComponentException
* @throws ExpressionEvaluationException
* @since 4.2
*/
public static boolean shouldExecute(Command command, boolean simplifyCriteria) throws TeiidComponentException, ExpressionEvaluationException {
return shouldExecute(command, simplifyCriteria, false);
}
public static boolean shouldExecute(Command command, boolean simplifyCriteria, boolean duringPlanning) throws TeiidComponentException, ExpressionEvaluationException {
int cmdType = command.getType();
Criteria criteria = null;
switch(cmdType) {
case Command.TYPE_QUERY:
QueryCommand queryCommand = (QueryCommand) command;
Limit limit = queryCommand.getLimit();
if (limit != null && limit.getRowLimit() instanceof Constant) {
Constant rowLimit = (Constant)limit.getRowLimit();
if (Integer.valueOf(0).equals(rowLimit.getValue())) {
return false;
}
}
if(queryCommand instanceof SetQuery) {
SetQuery union = (SetQuery) queryCommand;
boolean shouldExecute = false;
for (QueryCommand innerQuery : union.getQueryCommands()) {
boolean shouldInner = shouldExecute(innerQuery, simplifyCriteria, duringPlanning);
if(shouldInner) {
shouldExecute = true;
break;
}
}
return shouldExecute;
}
// Else this is a query
Query query = (Query) queryCommand;
criteria = query.getCriteria();
if(criteria == null) {
return true;
} else if(!EvaluatableVisitor.isFullyEvaluatable(criteria, duringPlanning)) {
// If there are elements present in the criteria,
// then we don't know the result, so assume we need to execute
return true;
} else if(Evaluator.evaluate(criteria)) {
if (simplifyCriteria) {
query.setCriteria(null);
}
return true;
}
if (query.hasAggregates() && query.getGroupBy() == null) {
return true;
}
break;
case Command.TYPE_INSERT:
Insert insert = (Insert) command;
QueryCommand expr = insert.getQueryExpression();
if (expr != null) {
return shouldExecute(expr, simplifyCriteria);
}
return true;
case Command.TYPE_UPDATE:
Update update = (Update) command;
if (update.getChangeList().isEmpty()) {
return false;
}
criteria = update.getCriteria();
// If there are elements present in the criteria,
// then we don't know the result, so assume we need to execute
if (criteria == null) {
return true;
}
if(!EvaluatableVisitor.isFullyEvaluatable(criteria, duringPlanning)) {
return true;
} else if(Evaluator.evaluate(criteria)) {
if (simplifyCriteria) {
update.setCriteria(null);
}
return true;
}
break;
case Command.TYPE_DELETE:
Delete delete = (Delete) command;
criteria = delete.getCriteria();
// If there are elements present in the criteria,
// then we don't know the result, so assume we need to execute
if (criteria == null) {
return true;
}
if(!EvaluatableVisitor.isFullyEvaluatable(criteria, duringPlanning)) {
return true;
} else if(Evaluator.evaluate(criteria)) {
if (simplifyCriteria) {
delete.setCriteria(null);
}
return true;
}
break;
default:
return true;
}
return false;
}
/**
* Returns whether the relational command is an update.
* @param command
* @return
* @since 4.2
*/
public static boolean isUpdate(Command command) {
int commandType = command.getType();
return commandType == Command.TYPE_INSERT ||
commandType == Command.TYPE_UPDATE ||
commandType == Command.TYPE_DELETE;
}
public static boolean hasOutputParams(Command command) {
boolean hasOutParams = false;
if (command instanceof StoredProcedure) {
StoredProcedure sp = (StoredProcedure)command;
hasOutParams = sp.returnParameters() && sp.getProjectedSymbols().size() > sp.getResultSetColumns().size();
}
return hasOutParams;
}
}