/* * 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.proc; import static org.teiid.query.analysis.AnalysisRecord.*; import org.teiid.client.plan.PlanNode; import org.teiid.common.buffer.BlockedException; import org.teiid.core.TeiidComponentException; import org.teiid.core.TeiidProcessingException; import org.teiid.logging.LogManager; import org.teiid.query.processor.relational.SubqueryAwareRelationalNode; import org.teiid.query.sql.lang.Criteria; import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor; /** * <p>This instruction an holds an if block and an else block and a criteria that determines * which block will be executed. These blocks are {@link Program} objects that could contain * nested if-else block. Therefore, this <code>ProgramInstruction</code> * implements an arbitrarily deep if-else if-....else block.</p> * * <p>During processing, the Criteria is evaluated and if it evaluates to true, * the "if" block is executed else the "else" block if there is one is executed. These * programs are placed on the {@link ProgramEnvironment#getProgramStack stack}.</p> */ public class IfInstruction extends ProgramInstruction { // the "if" block private Program ifProgram; // optional "else" block private Program elseProgram; // criteria on the "if" block private Criteria condition; /** * Constructor for IfInstruction. * @param condition The <code>Criteria</code> used to determine which block to execute * @param ifProgram The <code>Program</code> representing the "if" block * @param elseProgram The <code>Program</code> representing the "else" block */ public IfInstruction(Criteria condition, Program ifProgram, Program elseProgram) { this.condition = condition; this.ifProgram = ifProgram; this.elseProgram = elseProgram; } /** * Constructor for IfInstruction. * @param condition The <code>Criteria</code> used to determine which block to execute * @param ifProgram The <code>Program</code> representing the "if" block */ public IfInstruction(Criteria condition, Program ifProgram) { this(condition, ifProgram, null); } /** * This instruction will evaluate it's criteria, if it evaluates * to true, it will push the corresponding sub Program on to the top of the * program stack, and break from the loop. Regardless if whether any criteria * evaluate to true, this instruction will increment the program counter of the * current program. * @throws TeiidProcessingException * @see ProgramInstruction#process(ProcedurePlan) */ public void process(ProcedurePlan procEnv) throws BlockedException, TeiidComponentException, TeiidProcessingException { boolean evalValue = procEnv.evaluateCriteria(condition); if(evalValue) { LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, new Object[]{"IFInstruction: "+ //$NON-NLS-1$ " The criteria on the if block evaluated to true, processing the if block"}); //$NON-NLS-1$ //push the "if" Program onto the stack procEnv.push(ifProgram); } else if(elseProgram != null) { LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, new Object[]{"IFInstruction: "+ //$NON-NLS-1$ " The criteria on the if block evaluated to false, processing the else block"}); //$NON-NLS-1$ //push the "else" Program onto the stack procEnv.push(elseProgram); } } public Program getIfProgram(){ //Defect 13291 - made public to support changes to ProcedurePlan return this.ifProgram; } public Program getElseProgram(){ //Defect 13291 - made public to support changes to ProcedurePlan return this.elseProgram; } /** * Returns a deep clone */ public IfInstruction clone(){ Program cloneIf = this.ifProgram.clone(); Program cloneElse = null; if(elseProgram != null) { cloneElse = this.elseProgram.clone(); } IfInstruction clone = new IfInstruction(this.condition, cloneIf, cloneElse); return clone; } public String toString() { StringBuffer sb = new StringBuffer("IF INSTRUCTION: "); //$NON-NLS-1$ sb.append(condition); sb.append("\n").append(ifProgram); //$NON-NLS-1$ if (elseProgram!=null) { sb.append("\nELSE\n"); //$NON-NLS-1$ sb.append(elseProgram); } return sb.toString(); } public PlanNode getDescriptionProperties() { PlanNode props = new PlanNode("IF"); //$NON-NLS-1$ props.addProperty(PROP_CRITERIA, this.condition.toString()); props.addProperty(PROP_THEN, this.ifProgram.getDescriptionProperties()); if(elseProgram != null) { props.addProperty(PROP_ELSE, this.elseProgram.getDescriptionProperties()); } return props; } @Override public Boolean requiresTransaction(boolean transactionalReads) { Boolean conditionRequires = SubqueryAwareRelationalNode.requiresTransaction(transactionalReads, ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(condition)); if (conditionRequires != null && conditionRequires) { return true; } Boolean requires = ifProgram.requiresTransaction(transactionalReads); if (requires != null && requires) { return true; } if (elseProgram != null) { Boolean requiresElse = elseProgram.requiresTransaction(transactionalReads); if (requiresElse != null && requiresElse) { return true; } if (requiresElse == null) { return conditionRequires==null?true:null; } } if (requires == null) { return conditionRequires==null?true:null; } return conditionRequires; } }