/* * 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.HashMap; import java.util.List; import org.teiid.client.plan.PlanNode; import org.teiid.common.buffer.BlockedException; import org.teiid.common.buffer.BufferManager; import org.teiid.common.buffer.TupleBatch; import org.teiid.common.buffer.TupleBuffer; import org.teiid.core.TeiidComponentException; import org.teiid.core.TeiidProcessingException; import org.teiid.language.SQLConstants; import org.teiid.query.analysis.AnalysisRecord; import org.teiid.query.processor.ProcessorDataManager; import org.teiid.query.processor.ProcessorPlan; import org.teiid.query.processor.QueryProcessor; import org.teiid.query.sql.LanguageObject; import org.teiid.query.sql.lang.SetQuery; import org.teiid.query.sql.lang.WithQueryCommand; import org.teiid.query.sql.symbol.Expression; import org.teiid.query.tempdata.TempTableStore; import org.teiid.query.tempdata.TempTableStore.RecursiveTableProcessor; import org.teiid.query.tempdata.TempTableStore.TableProcessor; import org.teiid.query.tempdata.TempTableStore.TransactionMode; import org.teiid.query.util.CommandContext; /** */ public class RelationalPlan extends ProcessorPlan { // Initialize state - don't reset private RelationalNode root; private List<? extends Expression> outputCols; private List<WithQueryCommand> with; private TempTableStore tempTableStore; /** * Constructor for RelationalPlan. */ public RelationalPlan(RelationalNode node) { this.root = node; } public RelationalNode getRootNode() { return this.root; } public void setRootNode(RelationalNode root) { this.root = root; } public void setWith(List<WithQueryCommand> with) { this.with = with; } /** * @see ProcessorPlan#connectDataManager(ProcessorDataManager) */ public void initialize(CommandContext context, ProcessorDataManager dataMgr, BufferManager bufferMgr) { if (this.with != null) { context = context.clone(); tempTableStore = new TempTableStore(context.getConnectionId(), TransactionMode.NONE); tempTableStore.setParentTempTableStore(context.getTempTableStore()); context.setTempTableStore(tempTableStore); } setContext(context); connectExternal(this.root, context, dataMgr, bufferMgr); } static void connectExternal(RelationalNode node, CommandContext context, ProcessorDataManager dataMgr, BufferManager bufferMgr) { node.initialize(context, bufferMgr, dataMgr); RelationalNode[] children = node.getChildren(); int childCount = node.getChildCount(); for(int i=0; i<childCount; i++) { if(children[i] != null) { connectExternal(children[i], context, dataMgr, bufferMgr); } else { break; } } } /** * Get list of resolved elements describing output columns for this plan. * @return List of SingleElementSymbol */ public List<? extends Expression> getOutputElements() { return this.outputCols; } @Override public void open() throws TeiidComponentException, TeiidProcessingException { if (with != null && tempTableStore.getProcessors() == null) { HashMap<String, TableProcessor> processors = new HashMap<String, TableProcessor>(); tempTableStore.setProcessors(processors); for (WithQueryCommand withCommand : this.with) { if (withCommand.isRecursive()) { SetQuery setQuery = (SetQuery)withCommand.getCommand(); ProcessorPlan initial = setQuery.getLeftQuery().getProcessorPlan(); QueryProcessor withProcessor = new QueryProcessor(initial, getContext(), root.getBufferManager(), root.getDataManager()); processors.put(withCommand.getGroupSymbol().getName(), new RecursiveTableProcessor(withProcessor, withCommand.getColumns(), setQuery.getRightQuery().getProcessorPlan(), setQuery.isAll())); continue; } ProcessorPlan plan = withCommand.getCommand().getProcessorPlan(); QueryProcessor withProcessor = new QueryProcessor(plan, getContext(), root.getBufferManager(), root.getDataManager()); processors.put(withCommand.getGroupSymbol().getName(), new TableProcessor(withProcessor, withCommand.getColumns())); } } this.root.open(); } /** * @see ProcessorPlan#nextBatch() */ public TupleBatch nextBatch() throws BlockedException, TeiidComponentException, TeiidProcessingException { return this.root.nextBatch(); } public void close() throws TeiidComponentException { if (this.tempTableStore != null) { this.tempTableStore.removeTempTables(); if (this.tempTableStore.getProcessors() != null) { for (TableProcessor proc : this.tempTableStore.getProcessors().values()) { proc.close(); } this.tempTableStore.setProcessors(null); } } this.root.close(); } /** * @see org.teiid.query.processor.ProcessorPlan#reset() */ public void reset() { super.reset(); this.root.reset(); if (this.with != null) { for (WithQueryCommand withCommand : this.with) { if (withCommand.isRecursive()) { SetQuery setQuery = (SetQuery)withCommand.getCommand(); setQuery.getLeftQuery().getProcessorPlan().reset(); setQuery.getLeftQuery().getProcessorPlan().reset(); } else { withCommand.getCommand().getProcessorPlan().reset(); } } } } public String toString() { StringBuilder sb = new StringBuilder(); if (this.with != null) { sb.append(SQLConstants.Reserved.WITH); for (WithQueryCommand withCommand : this.with) { sb.append("\n"); //$NON-NLS-1$ sb.append(withCommand.getGroupSymbol()); if (withCommand.isRecursive()) { sb.append(" anchor\n").append(((SetQuery)withCommand.getCommand()).getLeftQuery().getProcessorPlan()); //$NON-NLS-1$ sb.append("recursive\n").append(((SetQuery)withCommand.getCommand()).getRightQuery().getProcessorPlan()); //$NON-NLS-1$ } else { sb.append("\n"); //$NON-NLS-1$ sb.append(withCommand.getCommand().getProcessorPlan()); } } sb.append("body\n"); //$NON-NLS-1$ } sb.append(this.root.toString()); return sb.toString(); } public RelationalPlan clone(){ RelationalPlan plan = new RelationalPlan((RelationalNode)root.clone()); plan.setOutputElements(outputCols); if (with != null) { List<WithQueryCommand> newWith = LanguageObject.Util.deepClone(this.with, WithQueryCommand.class); for (WithQueryCommand withQueryCommand : newWith) { if (withQueryCommand.isRecursive()) { SetQuery setQuery = (SetQuery)withQueryCommand.getCommand(); setQuery.getLeftQuery().setProcessorPlan(setQuery.getLeftQuery().getProcessorPlan().clone()); setQuery.getRightQuery().setProcessorPlan(setQuery.getRightQuery().getProcessorPlan().clone()); } else { withQueryCommand.getCommand().setProcessorPlan(withQueryCommand.getCommand().getProcessorPlan().clone()); } } plan.setWith(newWith); } return plan; } public PlanNode getDescriptionProperties() { PlanNode node = this.root.getDescriptionProperties(); if (this.with != null) { AnalysisRecord.addLanaguageObjects(node, AnalysisRecord.PROP_WITH, this.with); } return node; } /** * @param outputCols The outputCols to set. */ public void setOutputElements(List<? extends Expression> outputCols) { this.outputCols = outputCols; } @Override public Boolean requiresTransaction(boolean transactionalReads) { boolean txnWtih = false; if (this.with != null) { for (WithQueryCommand withCommand : this.with) { if (withCommand.isRecursive()) { SetQuery setQuery = (SetQuery)withCommand.getCommand(); Boolean leftRequires = setQuery.getLeftQuery().getProcessorPlan().requiresTransaction(transactionalReads); Boolean rightRequires = setQuery.getLeftQuery().getProcessorPlan().requiresTransaction(transactionalReads); if (Boolean.TRUE.equals(leftRequires) || Boolean.TRUE.equals(rightRequires)) { return true; } if (leftRequires == null || rightRequires == null) { if (txnWtih) { return true; } txnWtih = true; } } else { Boolean requires = withCommand.getCommand().getProcessorPlan().requiresTransaction(transactionalReads); if (Boolean.TRUE.equals(requires)) { return true; } if (requires == null) { if (txnWtih) { return true; } txnWtih = true; } } } } Boolean requires = requiresTransaction(transactionalReads, root); if (Boolean.TRUE.equals(requires)) { return true; } if (requires == null && txnWtih) { return true; } if (txnWtih || requires == null) { return null; } return false; } static Boolean requiresTransaction(boolean transactionalReads, RelationalNode node) { Boolean requiresTxn = node.requiresTransaction(transactionalReads); if (Boolean.TRUE.equals(requiresTxn)) { return true; } for (RelationalNode child : node.getChildren()) { if (child == null) { continue; } Boolean childRequires = requiresTransaction(transactionalReads, child); if (Boolean.TRUE.equals(childRequires)) { return true; } if (childRequires == null) { if (requiresTxn == null) { return true; } requiresTxn = null; } } return requiresTxn; } @Override public TupleBuffer getBuffer(int maxRows) throws BlockedException, TeiidComponentException, TeiidProcessingException { return root.getBuffer(maxRows); } @Override public boolean hasBuffer() { return root.hasBuffer(); } }