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

ru.curs.celesta.score.SQLGenerator Maven / Gradle / Ivy

The newest version!
package ru.curs.celesta.score;

import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

/**
 * Generator class of SQL expressions.
 */
public class SQLGenerator extends ExprVisitor {
    private final Deque stack = new LinkedList<>();

    /**
     * Returns SQL view of SQL expression.
     *
     * @param e expression
     * @return
     */
    final String generateSQL(Expr e) {
        try {
            e.accept(this);
        } catch (ParseException e1) {
            // This should never ever happen
            throw new RuntimeException(e1);
        }
        return stack.pop();
    }

    @Override
    final void visitBetween(Between expr) {
        String right2 = stack.pop();
        String right1 = stack.pop();
        String left = stack.pop();
        stack.push(String.format("%s BETWEEN %s AND %s", left, right1, right2));
    }

    @Override
    final void visitBinaryLogicalOp(BinaryLogicalOp expr) {
        StringBuilder result = new StringBuilder();
        String op = BinaryLogicalOp.OPS[expr.getOperator()];
        LinkedList operands = new LinkedList<>();
        for (int i = 0; i < expr.getOperands().size(); i++) {
            operands.push(stack.pop());
        }
        boolean needOp = false;
        for (String operand : operands) {
            if (needOp) {
                result.append(op);
            }
            result.append(operand);
            needOp = true;
        }
        stack.push(result.toString());
    }

    @Override
    final void visitBinaryTermOp(BinaryTermOp expr) {
        StringBuilder result = new StringBuilder();
        LinkedList operands = new LinkedList<>();
        for (int i = 0; i < expr.getOperands().size(); i++) {
            operands.push(stack.pop());
        }

        if (expr.getOperator() == BinaryTermOp.CONCAT) {
            concat(result, operands);
        } else {
            String op = BinaryTermOp.OPS[expr.getOperator()];
            boolean needOp = false;
            for (String operand : operands) {
                if (needOp) {
                    result.append(op);
                }
                result.append(operand);
                needOp = true;
            }
        }
        stack.push(result.toString());
    }

    @Override
    final void visitFieldRef(FieldRef expr) {
        StringBuilder result = new StringBuilder();

        if (expr.getTableNameOrAlias() != null) {
            if (quoteNames()) {
                result.append("\"");
            }
            result.append(expr.getTableNameOrAlias());
            if (quoteNames()) {
                result.append("\"");
            }
            result.append(".");
        }
        if (quoteNames()) {
            result.append("\"");
        }
        result.append(expr.getColumnName());
        if (quoteNames()) {
            result.append("\"");
        }
        stack.push(result.toString());
    }

    @Override
    void visitParameterRef(ParameterRef expr) {
        stack.push(paramLiteral(expr.getName()));
    }

    @Override
    final void visitIn(In expr) {
        StringBuilder result = new StringBuilder();
        LinkedList operands = new LinkedList<>();
        for (int i = 0; i < expr.getOperands().size(); i++) {
            operands.push(stack.pop());
        }
        result.append(stack.pop());
        result.append(" IN (");
        boolean needComma = false;
        for (String operand : operands) {
            if (needComma) {
                result.append(", ");
            }
            result.append(operand);
            needComma = true;
        }
        result.append(")");
        stack.push(result.toString());
    }

    @Override
    final void visitIsNull(IsNull expr) {
        stack.push(stack.pop() + " IS NULL");
    }

    @Override
    final void visitNotExpr(NotExpr expr) {
        stack.push("NOT " + stack.pop());
    }

    @Override
    final void visitRealLiteral(RealLiteral expr) {
        stack.push(expr.getLexValue());
    }

    @Override
    final void visitIntegerLiteral(IntegerLiteral expr) {
        stack.push(expr.getLexValue());
    }

    @Override
    final void visitParenthesizedExpr(ParenthesizedExpr expr) {
        stack.push("(" + stack.pop() + ")");
    }

    @Override
    final void visitRelop(Relop expr) {
        String right = stack.pop();
        String left = stack.pop();
        stack.push(left + Relop.OPS[expr.getRelop()] + right);
    }

    @Override
    final void visitTextLiteral(TextLiteral expr) {
        String val = checkForDate(expr.getLexValue());
        stack.push(val);
    }

    @Override
    final void visitBooleanLiteral(BooleanLiteral expr) {
        stack.push(boolLiteral(expr.getValue()));
    }

    @Override
    void visitUpper(Upper expr) {
        stack.push("UPPER(" + stack.pop() + ")");
    }

    @Override
    void visitLower(Lower expr) {
        stack.push("LOWER(" + stack.pop() + ")");
    }

    /**
     * Literals for boolean values.
     * @param val boolean value
     */
    protected String boolLiteral(boolean val) {
        return val ? "true" : "false";
    }

    /**
     * Literal for parameterized query parameter.
     * @param paramName name of the parameter
     */
    protected String paramLiteral(String paramName) {
        return "$" + paramName;
    }

    /**
     * Built-in function returning the current date.
     */
    protected String getDate() {
        return "GETDATE()";
    }

    /**
     * Check if value is date and translate it if needed.
     * @param lexValue Lex value
     */
    protected String checkForDate(String lexValue) {
        return lexValue;
    }

    final void visitUnaryMinus(UnaryMinus expr) {
        stack.push("-" + stack.pop());
    }

    @Override
    final void visitGetDate(GetDate expr) {
        stack.push(getDate());
    }


    /** Whether this generator should put all the names in quotes.
     *
     * @return true, if names should be quoted
     */
    protected boolean quoteNames() {
        return true;
    }

    /**
     * Concatenation operator.
     */
    protected String concat() {
        return " || ";
    }

    private void concat(StringBuilder result, List operands) {
        boolean needOp = false;
        for (String operand : operands) {
            if (needOp) {
                result.append(concat());
            }
            result.append(operand);
            needOp = true;
        }
    }

    /**
     * SQL preamble for view.
     * @param view view
     */
    protected String preamble(AbstractView view) {
        return String.format("create or replace view %s as", viewName(view));
    }

    /**
     * Formatted view name.
     * @param v view
     */
    protected String viewName(AbstractView v) {
        return String.format("%s.%s", v.getGrain().getQuotedName(), v.getQuotedName());
    }

    /**
     * Formatted table reference.
     * @param t table reference
     */
    protected String tableName(TableRef t) {
        return String.format("%s.%s as \"%s\"", t.getTable().getGrain().getQuotedName(), t.getTable().getQuotedName(),
                t.getAlias());
    }

    @Override
    void visitCount(Count expr) {
        stack.push("COUNT(*)");
    }

    @Override
    void visitSum(Sum expr) {
        stack.push("SUM(" + stack.pop() + ")");
    }

    @Override
    void visitMax(Max expr) {
        stack.push("MAX(" + stack.pop() + ")");
    }

    @Override
    void visitMin(Min expr) {
        stack.push("MIN(" + stack.pop() + ")");
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy