/*
* 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.sql.visitor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import org.teiid.designer.runtime.version.spi.ITeiidServerVersion;
import org.teiid.query.parser.LanguageVisitor;
import org.teiid.query.sql.lang.LanguageObject;
import org.teiid.query.sql.navigator.PreOrPostOrderNavigator;
import org.teiid.query.sql.symbol.AggregateSymbol;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.WindowFunction;
public class AggregateSymbolCollectorVisitor extends LanguageVisitor {
public static class AggregateStopNavigator extends PreOrPostOrderNavigator {
private Collection<? extends Expression> groupingCols;
private Collection<? super Expression> groupingColsUsed;
public AggregateStopNavigator(LanguageVisitor visitor, Collection<? super Expression> groupingColsUsed, Collection<? extends Expression> groupingCols) {
super(visitor, PreOrPostOrderNavigator.PRE_ORDER, false);
this.groupingCols = groupingCols;
this.groupingColsUsed = groupingColsUsed;
}
public AggregateStopNavigator(LanguageVisitor visitor, Collection<? extends Expression> groupingCols) {
super(visitor, PreOrPostOrderNavigator.PRE_ORDER, true);
this.groupingCols = groupingCols;
}
public void visit(AggregateSymbol obj) {
if (isLessThanTeiid8124()) {
// Visit aggregate symbol but do not dive into it's expression
preVisitVisitor(obj);
postVisitVisitor(obj);
return;
}
if (!obj.isWindowed()) {
// Visit aggregate symbol but do not dive into it's expression
preVisitVisitor(obj);
postVisitVisitor(obj);
} else {
super.visit(obj);
}
}
@Override
protected void visitNode(LanguageObject obj) {
if (groupingCols != null && obj instanceof Expression && groupingCols.contains(obj)) {
if (groupingColsUsed != null) {
groupingColsUsed.add((Expression)obj);
}
return;
}
super.visitNode(obj);
}
}
private Collection<? super AggregateSymbol> aggregates;
private Collection<? super ElementSymbol> otherElements;
private Collection<? super WindowFunction> windowFunctions;
public AggregateSymbolCollectorVisitor(ITeiidServerVersion teiidVersion, Collection<? super AggregateSymbol> aggregates, Collection<? super ElementSymbol> elements) {
super(teiidVersion);
this.aggregates = aggregates;
this.otherElements = elements;
}
public void visit(AggregateSymbol obj) {
if (aggregates != null && !obj.isWindowed()) {
this.aggregates.add(obj);
}
}
public void visit(WindowFunction windowFunction) {
if (this.windowFunctions != null) {
this.windowFunctions.add(windowFunction);
}
}
public void visit(ElementSymbol obj) {
if (this.otherElements != null && !obj.isExternalReference()) {
this.otherElements.add(obj);
}
}
public static final void getAggregates(LanguageObject obj,
Collection<? super AggregateSymbol> aggregates,
Collection<? super ElementSymbol> otherElements,
Collection<? super Expression> groupingColsUsed,
Collection<? super WindowFunction> windowFunctions,
Collection<? extends Expression> groupingCols) {
AggregateSymbolCollectorVisitor visitor = new AggregateSymbolCollectorVisitor(obj.getTeiidVersion(), aggregates, otherElements);
visitor.windowFunctions = windowFunctions;
AggregateStopNavigator asn = new AggregateStopNavigator(visitor, groupingColsUsed, groupingCols);
asn.visitNode(obj);
}
public static final Collection<AggregateSymbol> getAggregates(LanguageObject obj, boolean removeDuplicates) {
if (obj == null) {
return Collections.emptyList();
}
Collection<AggregateSymbol> aggregates = null;
if (removeDuplicates) {
aggregates = new LinkedHashSet<AggregateSymbol>();
} else {
aggregates = new ArrayList<AggregateSymbol>();
}
AggregateSymbolCollectorVisitor visitor = new AggregateSymbolCollectorVisitor(obj.getTeiidVersion(), aggregates, null);
AggregateStopNavigator asn = new AggregateStopNavigator(visitor, null, null);
obj.acceptVisitor(asn);
return aggregates;
}
}