package com.tesora.dve.tools.analyzer.stats; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.apache.log4j.Logger; import com.tesora.dve.sql.SchemaException; import com.tesora.dve.sql.expression.ExpressionUtils; import com.tesora.dve.sql.jg.JoinEdge; import com.tesora.dve.sql.jg.UncollapsedJoinGraph; import com.tesora.dve.sql.node.expression.AliasInstance; import com.tesora.dve.sql.node.expression.ColumnInstance; import com.tesora.dve.sql.node.expression.ExpressionAlias; import com.tesora.dve.sql.node.expression.ExpressionNode; import com.tesora.dve.sql.node.structural.JoinedTable; import com.tesora.dve.sql.node.structural.SortingSpecification; import com.tesora.dve.sql.schema.Column; import com.tesora.dve.sql.schema.Name; import com.tesora.dve.sql.schema.PETable; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.schema.Table; import com.tesora.dve.sql.statement.dml.SelectStatement; import com.tesora.dve.sql.util.Pair; import com.tesora.dve.tools.analyzer.StatementCounter; public class SelectStatementAnalysis extends StatementAnalysis<SelectStatement> { private static final Logger logger = Logger.getLogger(StatementCounter.class); public SelectStatementAnalysis(SchemaContext sc, String sql, int freq, SelectStatement stmt) { super(sc, sql, freq, stmt); } @Override public List<EquijoinInfo> getJoinInfo() { final UncollapsedJoinGraph ujg = new UncollapsedJoinGraph(getSchemaContext(), getStatement(), true); final ArrayList<EquijoinInfo> out = new ArrayList<EquijoinInfo>(); for (final JoinEdge je : ujg.getJoins()) { final JoinedTable jt = je.getJoin().getJoin(); final List<Name> usingSpec = (jt != null) ? jt.getUsingColSpec() : null; final ExpressionNode onClause = (jt != null) ? jt.getJoinOn() : null; final EquijoinInfo eji = new EquijoinInfo(je.getLHSTab().getAbstractTable(), je.getRHSTab().getAbstractTable(), je.getJoinType(), usingSpec, onClause, sc); for (final Pair<ColumnInstance, ColumnInstance> p : je.getSimpleColumns()) { eji.addJoinExpression(p.getFirst(), p.getSecond()); } out.add(eji); } return out; } @Override public void visit(StatsVisitor sv) { super.visit(sv); // have to normalize first to get the column names and aliases right final SelectStatement stmt = getStatement(); try { stmt.normalize(getSchemaContext()); } catch (final SchemaException se) { logger.warn("Could not normalize SELECT statement: " + stmt.getSQL(getSchemaContext())); return; } /* On Group By edge. */ final Set<Column<?>> groupByTuple = new LinkedHashSet<Column<?>>(); for (final SortingSpecification ss : getStatement().getGroupBysEdge()) { if (ss.getTarget() instanceof AliasInstance) { final AliasInstance ai = (AliasInstance) ss.getTarget(); final ExpressionAlias ea = ai.getTarget(); final ExpressionNode actual = ExpressionUtils.getTarget(ea); if (actual instanceof ColumnInstance) { final ColumnInstance ci = (ColumnInstance) actual; final Column<?> c = ci.getColumn(); groupByTuple.add(c); sv.onGroupBy(c, frequency); } } else if (ss.getTarget() instanceof ColumnInstance) { final ColumnInstance ci = (ColumnInstance) ss.getTarget(); final Column<?> c = ci.getColumn(); groupByTuple.add(c); sv.onGroupBy(c, frequency); } } if (!groupByTuple.isEmpty()) { sv.onGroupByColumnTuple(groupByTuple, frequency); } /* * On Order By edge. * Count only select statements involving a single table. * Statements with joins would benefit only if all the involved * tables were broadcast. * Multiple sorting columns count as one. */ if (getStatement().getOrderBysEdge().has()) { final Set<Table<?>> uniqueSortedTables = new HashSet<Table<?>>(getTables()); if (uniqueSortedTables.size() == 1) { final Table<?> table = uniqueSortedTables.iterator().next(); if (table instanceof PETable) { sv.onOrderBy((PETable) table, frequency); } } } } }