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

eu.clarussecure.proxy.protocol.plugins.pgsql.message.PgsqlColumnsFinder Maven / Gradle / Ivy

The newest version!
package eu.clarussecure.proxy.protocol.plugins.pgsql.message;

import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import net.sf.jsqlparser.expression.AllComparisonExpression;
import net.sf.jsqlparser.expression.AnalyticExpression;
import net.sf.jsqlparser.expression.AnyComparisonExpression;
import net.sf.jsqlparser.expression.Assignment;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.CaseExpression;
import net.sf.jsqlparser.expression.CastExpression;
import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
import net.sf.jsqlparser.expression.DateValue;
import net.sf.jsqlparser.expression.DoubleValue;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.expression.ExtractExpression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.HexValue;
import net.sf.jsqlparser.expression.IntervalExpression;
import net.sf.jsqlparser.expression.JdbcNamedParameter;
import net.sf.jsqlparser.expression.JdbcParameter;
import net.sf.jsqlparser.expression.JsonExpression;
import net.sf.jsqlparser.expression.KeepExpression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.MySQLGroupConcat;
import net.sf.jsqlparser.expression.Not;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.NumericBind;
import net.sf.jsqlparser.expression.OracleHierarchicalExpression;
import net.sf.jsqlparser.expression.OracleHint;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.RawStringValue;
import net.sf.jsqlparser.expression.RowConstructor;
import net.sf.jsqlparser.expression.SignedExpression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.TimeKeyExpression;
import net.sf.jsqlparser.expression.TimeValue;
import net.sf.jsqlparser.expression.TimestampValue;
import net.sf.jsqlparser.expression.UserVariable;
import net.sf.jsqlparser.expression.WhenClause;
import net.sf.jsqlparser.expression.WithinGroupExpression;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.Array;
import net.sf.jsqlparser.expression.operators.relational.ArrayElement;
import net.sf.jsqlparser.expression.operators.relational.Between;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
import net.sf.jsqlparser.expression.operators.relational.FromExpression;
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.IsExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.Matches;
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator;
import net.sf.jsqlparser.expression.operators.relational.RegExpMySQLOperator;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.SubSelect;

/**
 * Find all used tables within an select statement.
 */
public class PgsqlColumnsFinder implements ExpressionVisitor {

    private List>> expressionsWithColumns;
    private Map expressionsToParents;
    private Deque currentExpressions;

    public void parse(Expression expression) {
        expressionsWithColumns = new ArrayList<>();
        expressionsToParents = new HashMap<>();
        currentExpressions = new ArrayDeque<>();
        if (expression != null) {
            expression.accept(this);
        }
    }

    public List getColumns() {
        return expressionsWithColumns.stream().map(Map.Entry::getValue).flatMap(List::stream)
                .collect(Collectors.toList());
    }

    public List getExpressionsWithColumns() {
        return expressionsWithColumns.stream().map(Map.Entry::getKey).collect(Collectors.toList());
    }

    public List>> getExpressionsWithColumnsToColumns() {
        return expressionsWithColumns;
    }

    public Map getExpressionsToParents() {
        return expressionsToParents;
    }

    @Override
    public void visit(SubSelect subSelect) {
    }

    @Override
    public void visit(Assignment assignement) {
        visitBinaryExpression(assignement);
    }

    @Override
    public void visit(Addition addition) {
        visitBinaryExpression(addition);
    }

    @Override
    public void visit(AndExpression andExpression) {
        visitBinaryExpression(andExpression);
    }

    @Override
    public void visit(ArrayElement arrayElement) {
        expressionsToParents.put(arrayElement, currentExpressions.peek());
        currentExpressions.push(arrayElement);
        if (arrayElement.getLeftExpression() != null) {
            arrayElement.getLeftExpression().accept(this);
        }
        if (arrayElement.getIndex() != null) {
            arrayElement.getIndex().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(Array array) {
        expressionsToParents.put(array, currentExpressions.peek());
        currentExpressions.push(array);
        for (Expression element : array.getElements()) {
            element.accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(Between between) {
        expressionsToParents.put(between, currentExpressions.peek());
        currentExpressions.push(between);
        if (between.getLeftExpression() != null) {
            between.getLeftExpression().accept(this);
        }
        if (between.getBetweenExpressionStart() != null) {
            between.getBetweenExpressionStart().accept(this);
        }
        if (between.getBetweenExpressionEnd() != null) {
            between.getBetweenExpressionEnd().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(Column column) {
        if (column.getColumnName().charAt(0) == '$'
                && column.getColumnName().substring(1).chars().allMatch(c -> Character.isDigit(c))) {
            return;
        }
        Map.Entry> entry = expressionsWithColumns.isEmpty() ? null
                : expressionsWithColumns.get(expressionsWithColumns.size() - 1);
        Expression currentExpression = currentExpressions.peek();
        if (entry == null || entry.getKey() != currentExpression) {
            entry = new SimpleEntry<>(currentExpression, new ArrayList<>());
            expressionsWithColumns.add(entry);
        }
        entry.getValue().add(column);
    }

    @Override
    public void visit(Division division) {
        visitBinaryExpression(division);
    }

    @Override
    public void visit(DoubleValue doubleValue) {
    }

    @Override
    public void visit(EqualsTo equalsTo) {
        visitBinaryExpression(equalsTo);
    }

    @Override
    public void visit(IsExpression is) {
        visitBinaryExpression(is);
    }

    @Override
    public void visit(Function function) {
        expressionsToParents.put(function, currentExpressions.peek());
        currentExpressions.push(function);
        if (function.getParameters() != null) {
            for (Expression expression : function.getParameters().getExpressions()) {
                expression.accept(this);
            }
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(GreaterThan greaterThan) {
        visitBinaryExpression(greaterThan);
    }

    @Override
    public void visit(GreaterThanEquals greaterThanEquals) {
        visitBinaryExpression(greaterThanEquals);
    }

    @Override
    public void visit(InExpression inExpression) {
        expressionsToParents.put(inExpression, currentExpressions.peek());
        currentExpressions.push(inExpression);
        if (inExpression.getLeftExpression() != null) {
            inExpression.getLeftExpression().accept(this);
        } else if (inExpression.getLeftItemsList() != null) {
            // TODO ?
        }
        // TODO ?
        //inExpression.getRightItemsList().accept(this);
        currentExpressions.pop();
    }

    @Override
    public void visit(SignedExpression signedExpression) {
        expressionsToParents.put(signedExpression, currentExpressions.peek());
        currentExpressions.push(signedExpression);
        if (signedExpression.getExpression() != null) {
            signedExpression.getExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(IsNullExpression isNullExpression) {
        expressionsToParents.put(isNullExpression, currentExpressions.peek());
        currentExpressions.push(isNullExpression);
        if (isNullExpression.getLeftExpression() != null) {
            isNullExpression.getLeftExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(JdbcParameter jdbcParameter) {
    }

    @Override
    public void visit(LikeExpression likeExpression) {
        visitBinaryExpression(likeExpression);
    }

    @Override
    public void visit(FromExpression fromExpression) {
        visitBinaryExpression(fromExpression);
    }

    @Override
    public void visit(ExistsExpression existsExpression) {
        expressionsToParents.put(existsExpression, currentExpressions.peek());
        currentExpressions.push(existsExpression);
        if (existsExpression.getRightExpression() != null) {
            existsExpression.getRightExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(LongValue longValue) {
    }

    @Override
    public void visit(MinorThan minorThan) {
        visitBinaryExpression(minorThan);
    }

    @Override
    public void visit(MinorThanEquals minorThanEquals) {
        visitBinaryExpression(minorThanEquals);
    }

    @Override
    public void visit(Multiplication multiplication) {
        visitBinaryExpression(multiplication);
    }

    @Override
    public void visit(Not not) {
        expressionsToParents.put(not, currentExpressions.peek());
        currentExpressions.push(not);
        if (not.getExpression() != null) {
            not.getExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(NotEqualsTo notEqualsTo) {
        visitBinaryExpression(notEqualsTo);
    }

    @Override
    public void visit(NullValue nullValue) {
    }

    @Override
    public void visit(OrExpression orExpression) {
        visitBinaryExpression(orExpression);
    }

    @Override
    public void visit(Parenthesis parenthesis) {
        expressionsToParents.put(parenthesis, currentExpressions.peek());
        currentExpressions.push(parenthesis);
        if (parenthesis.getExpression() != null) {
            parenthesis.getExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(StringValue stringValue) {
    }

    @Override
    public void visit(RawStringValue stringValue) {
    }

    @Override
    public void visit(Subtraction subtraction) {
        visitBinaryExpression(subtraction);
    }

    public void visitBinaryExpression(BinaryExpression binaryExpression) {
        expressionsToParents.put(binaryExpression, currentExpressions.peek());
        currentExpressions.push(binaryExpression);
        if (binaryExpression.getLeftExpression() != null) {
            binaryExpression.getLeftExpression().accept(this);
        }
        if (binaryExpression.getLeftExpression() != null) {
            binaryExpression.getRightExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(DateValue dateValue) {
    }

    @Override
    public void visit(TimestampValue timestampValue) {
    }

    @Override
    public void visit(TimeValue timeValue) {
    }

    @Override
    public void visit(CaseExpression caseExpression) {
        expressionsToParents.put(caseExpression, currentExpressions.peek());
        currentExpressions.push(caseExpression);
        if (caseExpression.getSwitchExpression() != null) {
            caseExpression.getSwitchExpression().accept(this);
        }
        if (caseExpression.getWhenClauses() != null) {
            for (Expression expression : caseExpression.getWhenClauses()) {
                expression.accept(this);
            }
        }
        if (caseExpression.getElseExpression() != null) {
            caseExpression.getElseExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(WhenClause whenClause) {
        expressionsToParents.put(whenClause, currentExpressions.peek());
        currentExpressions.push(whenClause);
        if (whenClause.getWhenExpression() != null) {
            whenClause.getWhenExpression().accept(this);
        }
        if (whenClause.getThenExpression() != null) {
            whenClause.getThenExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(AllComparisonExpression allComparisonExpression) {
        // TODO ?
    }

    @Override
    public void visit(AnyComparisonExpression anyComparisonExpression) {
        // TODO ?
    }

    @Override
    public void visit(Concat concat) {
        visitBinaryExpression(concat);
    }

    @Override
    public void visit(Matches matches) {
        visitBinaryExpression(matches);
    }

    @Override
    public void visit(BitwiseAnd bitwiseAnd) {
        visitBinaryExpression(bitwiseAnd);
    }

    @Override
    public void visit(BitwiseOr bitwiseOr) {
        visitBinaryExpression(bitwiseOr);
    }

    @Override
    public void visit(BitwiseXor bitwiseXor) {
        visitBinaryExpression(bitwiseXor);
    }

    @Override
    public void visit(CastExpression cast) {
        expressionsToParents.put(cast, currentExpressions.peek());
        currentExpressions.push(cast);
        cast.getLeftExpression().accept(this);
        currentExpressions.pop();
    }

    @Override
    public void visit(Modulo modulo) {
        visitBinaryExpression(modulo);
    }

    @Override
    public void visit(AnalyticExpression analytic) {
    }

    @Override
    public void visit(ExtractExpression eexpr) {
    }

    @Override
    public void visit(IntervalExpression iexpr) {
    }

    @Override
    public void visit(JdbcNamedParameter jdbcNamedParameter) {
    }

    @Override
    public void visit(OracleHierarchicalExpression oexpr) {
        expressionsToParents.put(oexpr, currentExpressions.peek());
        currentExpressions.push(oexpr);
        if (oexpr.getStartExpression() != null) {
            oexpr.getStartExpression().accept(this);
        }

        if (oexpr.getConnectExpression() != null) {
            oexpr.getConnectExpression().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(RegExpMatchOperator rexpr) {
        visitBinaryExpression(rexpr);
    }

    @Override
    public void visit(RegExpMySQLOperator rexpr) {
        visitBinaryExpression(rexpr);
    }

    @Override
    public void visit(JsonExpression jsonExpr) {
        expressionsToParents.put(jsonExpr, currentExpressions.peek());
        currentExpressions.push(jsonExpr);
        if (jsonExpr.getColumn() != null) {
            jsonExpr.getColumn().accept(this);
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(JsonOperator jsonExpr) {
    }

    @Override
    public void visit(WithinGroupExpression wgexpr) {
        expressionsToParents.put(wgexpr, currentExpressions.peek());
        currentExpressions.push(wgexpr);
        if (wgexpr.getExprList() != null) {
            for (Expression expression : wgexpr.getExprList().getExpressions()) {
                expression.accept(this);
            }
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(UserVariable var) {
    }

    @Override
    public void visit(NumericBind bind) {

    }

    @Override
    public void visit(KeepExpression aexpr) {
        // TODO ?
    }

    @Override
    public void visit(MySQLGroupConcat groupConcat) {
        // TODO ?
    }

    @Override
    public void visit(RowConstructor rowConstructor) {
        expressionsToParents.put(rowConstructor, currentExpressions.peek());
        currentExpressions.push(rowConstructor);
        if (rowConstructor.getExprList() != null) {
            for (Expression expr : rowConstructor.getExprList().getExpressions()) {
                expr.accept(this);
            }
        }
        currentExpressions.pop();
    }

    @Override
    public void visit(HexValue hexValue) {

    }

    @Override
    public void visit(OracleHint hint) {
    }

    @Override
    public void visit(TimeKeyExpression timeKeyExpression) {
    }

    @Override
    public void visit(DateTimeLiteralExpression literal) {
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy