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 org.apache.log4j.Logger; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.sql.ParserException.Pass; import com.tesora.dve.sql.SchemaException; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.statement.Statement; import com.tesora.dve.sql.statement.dml.DMLStatement; import com.tesora.dve.sql.statement.dml.DeleteStatement; import com.tesora.dve.sql.statement.dml.InsertStatement; import com.tesora.dve.sql.statement.dml.ProjectingStatement; import com.tesora.dve.sql.statement.dml.SelectStatement; import com.tesora.dve.sql.statement.dml.UpdateStatement; import com.tesora.dve.tools.analyzer.Analyzer; import com.tesora.dve.tools.analyzer.AnalyzerOptions; import com.tesora.dve.tools.analyzer.SourcePosition; import com.tesora.dve.tools.analyzer.sources.FrequenciesSource; public class StatementAnalyzer extends Analyzer { private static final Logger logger = Logger.getLogger(StatementAnalyzer.class); private final StatsVisitor visitor; public StatementAnalyzer(AnalyzerOptions opts, StatsVisitor sv) throws Throwable { super(opts); this.visitor = sv; } @Override public void onFinished() throws PEException { // noop } @SuppressWarnings("unchecked") @Override public void onStatement(String sql, SourcePosition sp, Statement s) throws Throwable { if (s instanceof DMLStatement) { final Integer freqObj = sp.getLineInfo().getIntOption(FrequenciesSource.FREQUENCY_TAG); final int freq = (freqObj == null ? 0 : freqObj.intValue()); final DMLStatement dmls = (DMLStatement) s; final StatementAnalysis<?> stmtStats = build(tee.getPersistenceContext(), sql, freq, dmls); visitor.beginStmt(stmtStats); visitStatement(tee.getPersistenceContext(), stmtStats); for (final ProjectingStatement ps : dmls.getDerivedInfo().getAllNestedQueries()) { final StatementAnalysis<ProjectingStatement> nested = (StatementAnalysis<ProjectingStatement>) build(tee.getPersistenceContext(), null, freq, ps); visitor.beginStmt(nested); visitStatement(tee.getPersistenceContext(), nested); visitor.endStmt(nested); } visitor.endStmt(stmtStats); } } private void visitStatement(SchemaContext db, StatementAnalysis<?> stmtStats) { try { stmtStats.visit(visitor); } catch (final SchemaException se) { final String sql = stmtStats.getStatement().getSQL(db); throw new SchemaException(Pass.PLANNER, "Unable to obtain stats (freq=" + stmtStats.frequency + ") from " + sql, se); } } @SuppressWarnings({ "rawtypes", "unchecked" }) private StatementAnalysis<?> build(SchemaContext db, String sql, int freq, DMLStatement dmls) { StatementAnalysis<?> out = null; if (dmls instanceof SelectStatement) { out = new SelectStatementAnalysis(db, sql, freq, (SelectStatement) dmls); } else if (dmls instanceof InsertStatement) { out = new InsertStatementAnalysis(db, sql, freq, (InsertStatement) dmls); } else if (dmls instanceof UpdateStatement) { out = new UpdateStatementAnalysis(db, sql, freq, (UpdateStatement) dmls); } else if (dmls instanceof DeleteStatement) { out = new DeleteStatementAnalysis(db, sql, freq, (DeleteStatement) dmls); } else { out = new StatementAnalysis(db, sql, freq, dmls); } return out; } @Override public void onException(String sql, SourcePosition sp, Throwable t) { logger.error("An error occured when analyzing [" + sp.getLineInfo().toString() + "]: " + sql, t); } @Override public void onNotice(String sql, SourcePosition sp, String message) { logger.warn(message + " [" + sp.getLineInfo().toString() + "]: " + sql); } }