All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.novartis.opensource.yada.Parser Maven / Gradle / Ivy

/**
 * Copyright 2016 Novartis Institutes for BioMedical Research Inc.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.novartis.opensource.yada;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.JdbcParameter;
import net.sf.jsqlparser.expression.YADAMarkupParameter;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.SetStatement;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
import net.sf.jsqlparser.statement.Statements;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.create.index.CreateIndex;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.create.view.AlterView;
import net.sf.jsqlparser.statement.create.view.CreateView;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.drop.Drop;
import net.sf.jsqlparser.statement.execute.Execute;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.merge.Merge;
import net.sf.jsqlparser.statement.replace.Replace;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.truncate.Truncate;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.util.deparser.DeleteDeParser;

import org.apache.log4j.Logger;

/**
 * An implementation of {@link StatementVisitor} which currently handles
 * {@code SELECT}, {@code INSERT}, {@code UPDATE}, and {@code DELETE} statements (but not 
 * {@code REPLACE}, {@code TRUNCATE}, or {@code DROP}, yet).  The class also indexes columns parsed out of statements 
 * into 3 categories: 
 * 
    *
  • any column referenced
  • *
  • any column mapped ot a JDBC parameter
  • *
  • any column referenced by an {@code IN} clause
  • *
* @author David Varon * */ public class Parser implements StatementVisitor { /** * Local logger handle */ private static Logger l = Logger.getLogger(Parser.class); /** * Constant equal to: {@value} */ public static final String COLUMNS = "columns"; /** * Constant equal to: {@value} */ public static final String JDBC_COLUMNS = "jdbcColumns"; /** * Constant equal to: {@value} */ public static final String IN_COLUMNS = "inColumns"; /** * Constant equal to: {@value} */ public static final String STATEMENT = "statement"; /** * Constant equal to: {@value} */ @SuppressWarnings("unused") private static final String JDBC_PARAMETER = "?"; /** * Constant equal to: {@value} */ public static final String TYPE = "type"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String SELECT = "SELECT"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String UPDATE = "UPDATE"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String INSERT = "INSERT"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String DELETE = "DELETE"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String CALL = "CALL"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String JDBC = "JDBC"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String REST = "REST"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String SOAP = "SOAP"; /** * Constant value equal to: {@value} * @since 0.4.0.0 */ public static final String FILE = "FILE"; /** * Required jsqlparser class to execute parsing */ private CCJSqlParserManager parserManager = new CCJSqlParserManager(); /** * Instance var to hold Statement objects */ private Statement statement = null; /** * Instance var to hold query type value */ private String type = ""; /** * Index of all SQL columns created by deparser */ private ArrayList cols = new ArrayList<>(); /** * Index of all SQL columns associated to JDBC parameters and created by the deparser */ private ArrayList jdbcCols = new ArrayList<>(); /** * Index of all SQL columns found in IN clauses and created by the deparser */ private ArrayList inCols = new ArrayList<>(); /** * Buffer used by jsqlparser to store SQL fragments */ private StringBuilder buf = new StringBuilder();//new StringBuffer(); /** * Local expression deparser */ private YADAExpressionDeParser yedp = new YADAExpressionDeParser(); /** * @return the type of query, in an array */ public String[] getType() { return new String[]{this.type}; } /** * Standard mutator of variable * @param type the type of query */ public void setType(String type) { this.type = type; } /** * Evaluates {@code SELECT} statement, setting {@link #type} to {@link #SELECT}, * drilling into the select body, and indexing any columns encountered. */ @Override public void visit(Select select) { YADASelectDeParser selectVisitor = (YADASelectDeParser)getExpressionDeParser().getSelectVisitor(); select.getSelectBody().accept(selectVisitor); addColumnNamesToLists(); setType(SELECT); } /** * Evalates {@code DELETE} statement, setting {@link #type} to {@link #DELETE}, * deparsing the statement, and indexing any columns encountered. */ @Override public void visit(Delete delete) { DeleteDeParser dp = new DeleteDeParser(getExpressionDeParser(), getStringBuffer()); dp.deParse(delete); addColumnNamesToLists(); setType(DELETE); } /** * Evalates {@code UPDATE} statement, setting {@link #type} to {@link #UPDATE}, * deparsing the statement, and indexing any columns encountered. * This method also more actively handles expressions and functions encountered * in the statement body. */ @Override public void visit(Update update) { List columns = update.getColumns(); getColumnList().addAll(columns); for (int i = 0; i < columns.size(); i++) { Column column = columns.get(i); Expression expression = update.getExpressions().get(i); if (expression instanceof YADAMarkupParameter) { getJdbcColumnList().add(column); } else if (expression instanceof Function) { Function function = (Function)expression; ExpressionList paramList = function.getParameters(); for(int j=0;j expressions = getExpressionDeParser().getExpressions(); List columns = insert.getColumns(); getColumnList().addAll(columns); for (int i = 0; i < columns.size(); i++) { if(expressions.get(i) instanceof YADAMarkupParameter) { l.debug("Adding JDBC column [" + columns.get(i) + "] to list"); getJdbcColumnList().add(columns.get(i)); } else if (expressions.get(i) instanceof Function) { Function function = (Function)expressions.get(i); ExpressionList paramList = function.getParameters(); for(int j=0;j parse(String sql) throws YADAParserException { Hashtable colLists = new Hashtable<>(); try { this.setStatement(this.parserManager.parse(new StringReader(sql))); processStatement(this.getStatement()); String[] jdbcColumns = new String[getJdbcColumnList().size()]; String[] columns = new String[getColumnList().size()]; String[] inColumns = new String[getInColumnList().size()]; for (int i = 0; i < this.cols.size(); i++) { columns[i] = this.cols.get(i).getColumnName().toUpperCase(); } for (int i = 0; i < this.jdbcCols.size(); i++) { jdbcColumns[i] = this.jdbcCols.get(i).getColumnName().toUpperCase(); } for (int i = 0; i < this.inCols.size(); i++) { inColumns[i] = this.inCols.get(i).getColumnName().toUpperCase(); } colLists.put(TYPE, getType()); colLists.put(COLUMNS, columns); colLists.put(JDBC_COLUMNS, jdbcColumns); colLists.put(IN_COLUMNS, inColumns); } catch (JSQLParserException e) { String msg = "The query was not parsable. Other than the query being invalid, this could be because it is non-compliant, unsupported, or not SQL"; l.error(msg + "\n" + sql); throw new YADAParserException(msg, e); } finally { if (l.isDebugEnabled()) { for (String list : colLists.keySet()) { String[] columns = colLists.get(list); for (String col : columns) { l.debug("[" + list + "] contains [" + col + "]"); } } } } return colLists; } /** * Kick off the recursive accept/visit deparsing action * @param statementToProcess the deparsed query */ private void processStatement(Statement statementToProcess) { // set the ivar this.setStatement(statementToProcess); // set the deparser and the buffer getExpressionDeParser().setBuffer(getStringBuffer()); // proceed to process the statement this.getStatement().accept(this); } /** * Dump column metadata collected by deparsing into indices */ private void addColumnNamesToLists() { getColumnList().addAll(getExpressionDeParser().getColumns()); getJdbcColumnList().addAll(getExpressionDeParser().getJdbcColumns()); getInColumnList().addAll(getExpressionDeParser().getInColumns()); } /** * Standard accessor for variable * @return the expression deparser */ private YADAExpressionDeParser getExpressionDeParser() { return this.yedp; } /** * Standard accessor for variable * @return the internal string buffer */ private StringBuilder getStringBuffer() { return this.buf; } /** * Standard accessor for variable * @return the column index */ private ArrayList getColumnList() { return this.cols; } /** * Standard accessor for variable * @return the jdbc column index */ private ArrayList getJdbcColumnList() { return this.jdbcCols; } /** * Standard accessor for variable * @return the "in" column index */ private ArrayList getInColumnList() { return this.inCols; } /** * @return the statement * @since 0.7.0.0 */ public Statement getStatement() { return this.statement; } /** * @param statement the statement to set * @since 0.7.0.0 */ public void setStatement(Statement statement) { this.statement = statement; } @Override public void visit(CreateIndex createIndex) { // nothing to do } @Override public void visit(CreateView createView) { // nothing to do } @Override public void visit(AlterView alterView) { // nothing to do } @Override public void visit(Alter alter) { // nothing to do } @Override public void visit(Statements stmts) { // nothing to do } @Override public void visit(Execute execute) { // nothing to do } @Override public void visit(SetStatement set) { // nothing to do } @Override public void visit(Merge merge) { // nothing to do } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy