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

org.dbflute.twowaysql.SqlAnalyzer Maven / Gradle / Ivy

/*
 * Copyright 2014-2020 the original author or authors.
 *
 * 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 org.dbflute.twowaysql;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.dbflute.exception.ParameterCommentNotAllowedInitialCharacterException;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.twowaysql.context.CommandContext;
import org.dbflute.twowaysql.context.CommandContextCreator;
import org.dbflute.twowaysql.exception.EndCommentNotFoundException;
import org.dbflute.twowaysql.exception.ForCommentExpressionEmptyException;
import org.dbflute.twowaysql.exception.IfCommentConditionEmptyException;
import org.dbflute.twowaysql.factory.DefaultNodeAdviceFactory;
import org.dbflute.twowaysql.factory.NodeAdviceFactory;
import org.dbflute.twowaysql.factory.SqlAnalyzerFactory;
import org.dbflute.twowaysql.node.BeginNode;
import org.dbflute.twowaysql.node.BindVariableNode;
import org.dbflute.twowaysql.node.ElseNode;
import org.dbflute.twowaysql.node.EmbeddedVariableNode;
import org.dbflute.twowaysql.node.ForNode;
import org.dbflute.twowaysql.node.ForNode.LoopVariableType;
import org.dbflute.twowaysql.node.IfNode;
import org.dbflute.twowaysql.node.LoopAbstractNode;
import org.dbflute.twowaysql.node.LoopFirstNode;
import org.dbflute.twowaysql.node.LoopLastNode;
import org.dbflute.twowaysql.node.LoopNextNode;
import org.dbflute.twowaysql.node.Node;
import org.dbflute.twowaysql.node.RootNode;
import org.dbflute.twowaysql.node.SqlConnectorAdjustable;
import org.dbflute.twowaysql.node.SqlConnectorNode;
import org.dbflute.twowaysql.node.SqlPartsNode;
import org.dbflute.twowaysql.style.BoundDateDisplayStyle;
import org.dbflute.util.Srl;

/**
 * @author modified by jflute (originated in S2Dao)
 */
public class SqlAnalyzer {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    protected static final NodeAdviceFactory _defaultNodeAdviceFactory = new DefaultNodeAdviceFactory();

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected final String _specifiedSql;
    protected final boolean _blockNullParameter;
    protected final SqlTokenizer _tokenizer;
    protected boolean _overlookNativeBinding; // unused on DBFlute, for general purpose
    protected boolean _switchBindingToReplaceOnlyEmbedded; // dangerous, unused on DBFlute, for general purpose
    protected final Stack _nodeStack = new Stack();
    protected boolean _inBeginScope;
    protected List _researchIfCommentList;
    protected List _researchForCommentList;
    protected List _researchBindVariableCommentList;
    protected List _researchEmbeddedVariableCommentList;

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    public SqlAnalyzer(String sql, boolean blockNullParameter) {
        _specifiedSql = filterAtFirst(sql);
        _blockNullParameter = blockNullParameter;
        _tokenizer = createSqlTokenizer(_specifiedSql);
    }

    protected String filterAtFirst(String sql) {
        return removeTerminalMarkAtFirst(trimSqlAtFirst(sql));
    }

    protected String trimSqlAtFirst(String sql) {
        return sql.trim();
    }

    protected String removeTerminalMarkAtFirst(String sql) {
        return sql.endsWith(";") ? sql.substring(0, sql.length() - 1) : sql;
    }

    protected SqlTokenizer createSqlTokenizer(String sql) {
        final SqlTokenizer tokenizer = newSqlTokenizer(sql);
        if (_overlookNativeBinding) {
            tokenizer.overlookNativeBinding();
        }
        return tokenizer;
    }

    protected SqlTokenizer newSqlTokenizer(String sql) {
        return new SqlTokenizer(sql);
    }

    // -----------------------------------------------------
    //                                                Option
    //                                                ------
    /**
     * [Attention] unused on DBFlute, for general purpose
     * @return this. (NotNull)
     */
    public SqlAnalyzer overlookNativeBinding() {
        _overlookNativeBinding = true;
        _tokenizer.overlookNativeBinding(); // reflect existing instance
        return this;
    }

    /**
     * [Attention] dangerous, be careful, and unused on DBFlute, basically for general purpose
     * @return this. (NotNull)
     */
    public SqlAnalyzer switchBindingToReplaceOnlyEmbedded() {
        _switchBindingToReplaceOnlyEmbedded = true;
        return this;
    }

    // ===================================================================================
    //                                                                             Analyze
    //                                                                             =======
    public Node analyze() {
        push(createRootNode()); // root node of all
        while (SqlTokenizer.EOF != _tokenizer.next()) {
            parseToken();
        }
        return pop();
    }

    protected RootNode createRootNode() {
        return new RootNode();
    }

    protected void parseToken() {
        switch (_tokenizer.getTokenType()) {
        case SqlTokenizer.SQL:
            parseSql();
            break;
        case SqlTokenizer.COMMENT:
            parseComment();
            break;
        case SqlTokenizer.ELSE:
            parseElse();
            break;
        case SqlTokenizer.BIND_VARIABLE:
            parseBindVariable();
            break;
        }
    }

    // ===================================================================================
    //                                                                           SQL Parts
    //                                                                           =========
    protected void parseSql() {
        final String sql;
        {
            String token = _tokenizer.getToken();
            if (isElseMode()) {
                token = replaceString(token, "--", "");
            }
            sql = token;
        }
        final Node node = peek();
        if (isSqlConnectorAdjustable(node)) {
            processSqlConnectorAdjustable(node, sql);
        } else {
            node.addChild(createSqlPartsNodeOutOfConnector(node, sql));
        }
    }

    protected void processSqlConnectorAdjustable(Node node, String sql) {
        final SqlTokenizer st = createSqlTokenizer(sql);
        st.skipWhitespace();
        final String skippedToken = st.skipToken(); // determination for and/or (also skip process)
        st.skipWhitespace();
        if (processSqlConnectorMark(node, sql)) { // comma, ...
            return;
        }
        if (processSqlConnectorCondition(node, st, skippedToken)) { // and/or
            return;
        }
        // is not connector
        node.addChild(createSqlPartsNodeThroughConnector(node, sql));
    }

    protected boolean processSqlConnectorMark(Node node, String sql) {
        if (doProcessSqlConnectorMark(node, sql, ",")) { // comma
            return true;
        }
        return false;
    }

    protected boolean doProcessSqlConnectorMark(Node node, String sql, String mark) {
        final String ltrimmedSql = Srl.ltrim(sql); // for mark
        if (ltrimmedSql.startsWith(mark)) { // is connector
            final String markSpace = mark + " ";
            final String realMark = ltrimmedSql.startsWith(markSpace) ? markSpace : mark;
            node.addChild(createSqlConnectorNode(node, realMark, ltrimmedSql.substring(realMark.length())));
            return true;
        }
        return false;
    }

    protected boolean processSqlConnectorCondition(Node node, SqlTokenizer st, String skippedToken) {
        if ("and".equalsIgnoreCase(skippedToken) || "or".equalsIgnoreCase(skippedToken)) { // is connector
            node.addChild(createSqlConnectorNode(node, st.getBefore(), st.getAfter()));
            return true;
        }
        return false;
    }

    protected boolean isSqlConnectorAdjustable(Node node) {
        if (node.getChildSize() > 0) {
            return false;
        }
        return (node instanceof SqlConnectorAdjustable) && !isTopBegin(node);
    }

    // ===================================================================================
    //                                                                         SQL Comment
    //                                                                         ===========
    protected void parseComment() {
        final String comment = _tokenizer.getToken();
        if (isTargetComment(comment)) { // parameter comment
            if (isBeginComment(comment)) {
                parseBegin();
            } else if (isIfComment(comment)) {
                parseIf();
            } else if (isForComment(comment)) {
                parseFor();
            } else if (isLoopVariableComment(comment)) {
                parseLoopVariable();
            } else if (isEndComment(comment)) {
                return;
            } else {
                parseCommentBindVariable();
            }
        } else if (Srl.is_NotNull_and_NotTrimmedEmpty(comment)) { // plain comment
            if (isFrequentlyMistakePattern(comment)) {
                throwParameterCommentNotAllowedInitialCharacterException(comment);
            }
            final String before = _tokenizer.getBefore();
            final String content = before.substring(before.lastIndexOf("/*"));
            peek().addChild(createSqlPartsNode(content));
        }
    }

    protected boolean isTargetComment(String comment) {
        if (Srl.is_Null_or_TrimmedEmpty(comment)) {
            return false;
        }
        if (!isSpecialInitChar(comment) && !isTargetCommentFirstChar(comment)) {
            return false;
        }
        return true;
    }

    protected boolean isSpecialInitChar(String comment) {
        return comment.startsWith(ForNode.CURRENT_VARIABLE); // except current variable from check
    }

    protected boolean isTargetCommentFirstChar(String comment) {
        return Character.isJavaIdentifierStart(comment.charAt(0));
    }

    protected boolean isFrequentlyMistakePattern(String comment) {
        return comment.startsWith(" pmb."); // e.g. /* pmb.memberName */
    }

    protected void throwParameterCommentNotAllowedInitialCharacterException(String comment) {
        final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
        br.addNotice("The initial character in the parameter comment was not allowed.");
        br.addItem("Advice");
        br.addElement("The parameter comment should start with identifier.");
        br.addElement("Fix like this:");
        br.addElement("  (x) - /* pmb.memberName */");
        br.addElement("  (o) - /*pmb.memberName*/");
        br.addElement("");
        br.addElement("Or rewrite your plain comment:");
        br.addElement("  (x) - /* pmb. so ...(as plain comment) */");
        br.addElement("  (o) - /* this is pmb. so ...(as plain comment) */");
        br.addItem("Checked Comment");
        br.addElement("/*" + comment + "*/");
        br.addItem("Specified SQL");
        br.addElement(_specifiedSql);
        final String msg = br.buildExceptionMessage();
        throw new ParameterCommentNotAllowedInitialCharacterException(msg);
    }

    // ===================================================================================
    //                                                                       BEGIN Comment
    //                                                                       =============
    protected boolean isBeginComment(String comment) {
        return BeginNode.MARK.equals(comment);
    }

    protected void parseBegin() {
        final BeginNode beginNode = createBeginNode();
        try {
            _inBeginScope = true;
            peek().addChild(beginNode);
            push(beginNode);
            parseEnd();
        } finally {
            _inBeginScope = false;
        }
    }

    protected BeginNode createBeginNode() {
        return newBeginNode(_inBeginScope);
    }

    protected BeginNode newBeginNode(boolean inBeginScope) {
        return new BeginNode(inBeginScope);
    }

    protected boolean isTopBegin(Node node) {
        if (!(node instanceof BeginNode)) {
            return false;
        }
        return !((BeginNode) node).isNested();
    }

    protected boolean isNestedBegin(Node node) {
        if (!(node instanceof BeginNode)) {
            return false;
        }
        return ((BeginNode) node).isNested();
    }

    // ===================================================================================
    //                                                                          IF Comment
    //                                                                          ==========
    protected boolean isIfComment(String comment) {
        return comment.startsWith(IfNode.PREFIX);
    }

    protected void parseIf() {
        final String comment = _tokenizer.getToken();
        final String condition = comment.substring(IfNode.PREFIX.length()).trim();
        if (Srl.is_Null_or_TrimmedEmpty(condition)) {
            throwIfCommentConditionEmptyException();
        }
        final IfNode ifNode = createIfNode(condition);
        peek().addChild(ifNode);
        push(ifNode);
        parseEnd();
    }

    protected IfNode createIfNode(String expr) {
        researchIfNeeds(_researchIfCommentList, expr); // for research
        return newIfNode(expr, _specifiedSql);
    }

    protected IfNode newIfNode(String expr, String specifiedSql) {
        return new IfNode(expr, specifiedSql);
    }

    protected void throwIfCommentConditionEmptyException() {
        final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
        br.addNotice("The condition of IF comment was empty!");
        br.addItem("Advice");
        br.addElement("Please confirm the IF comment expression.");
        br.addElement("Your IF comment might not have a condition.");
        br.addElement("For example:");
        br.addElement("  (x) - /*IF */XXX_ID = /*pmb.xxxId*/3/*END*/");
        br.addElement("  (o) - /*IF pmb.xxxId != null*/XXX_ID = /*pmb.xxxId*/3/*END*/");
        br.addItem("IF Comment");
        br.addElement(_tokenizer.getToken());
        br.addItem("Specified SQL");
        br.addElement(_specifiedSql);
        final String msg = br.buildExceptionMessage();
        throw new IfCommentConditionEmptyException(msg);
    }

    // ===================================================================================
    //                                                                        ELSE Comment
    //                                                                        ============
    protected void parseElse() {
        final Node parent = peek();
        if (!(parent instanceof IfNode)) {
            return;
        }
        final IfNode ifNode = (IfNode) pop();
        final ElseNode elseNode = createElseNode();
        ifNode.setElseNode(elseNode);
        push(elseNode);
        _tokenizer.skipWhitespace();
    }

    protected ElseNode createElseNode() {
        return newElseNode();
    }

    protected ElseNode newElseNode() {
        return new ElseNode();
    }

    // ===================================================================================
    //                                                                         FOR Comment
    //                                                                         ===========
    protected boolean isForComment(String comment) {
        return comment.startsWith(ForNode.PREFIX);
    }

    protected void parseFor() {
        final String comment = _tokenizer.getToken();
        final String condition = comment.substring(ForNode.PREFIX.length()).trim();
        if (Srl.is_Null_or_TrimmedEmpty(condition)) {
            throwForCommentExpressionEmptyException();
        }
        final ForNode forNode = createForNode(condition);
        peek().addChild(forNode);
        push(forNode);
        parseEnd();
    }

    protected ForNode createForNode(String expr) {
        researchIfNeeds(_researchForCommentList, expr); // for research
        return newForNode(expr, _specifiedSql, getNodeAdviceFactory());
    }

    protected ForNode newForNode(String expr, String specifiedSql, NodeAdviceFactory adviceFactory) {
        return new ForNode(expr, specifiedSql, adviceFactory);
    }

    protected boolean isLoopVariableComment(String comment) {
        return comment.startsWith(LoopFirstNode.MARK) || comment.startsWith(LoopNextNode.MARK) || comment.startsWith(LoopLastNode.MARK);
    }

    protected void parseLoopVariable() { // should be in FOR comment scope
        final String comment = _tokenizer.getToken();
        final String code = Srl.substringFirstFront(comment, " ");
        if (Srl.is_Null_or_TrimmedEmpty(code)) { // no way
            String msg = "Unknown loop variable comment: " + comment;
            throw new IllegalStateException(msg);
        }
        final LoopVariableType type = LoopVariableType.codeOf(code);
        if (type == null) { // no way
            String msg = "Unknown loop variable comment: " + comment;
            throw new IllegalStateException(msg);
        }
        final String condition = comment.substring(type.name().length()).trim();
        final LoopAbstractNode loopFirstNode = createLoopFirstNode(condition, type);
        peek().addChild(loopFirstNode);
        if (Srl.count(condition, "'") < 2) {
            push(loopFirstNode);
            parseEnd();
        }
    }

    protected LoopAbstractNode createLoopFirstNode(String expr, LoopVariableType type) {
        return type.createNode(expr, _specifiedSql);
    }

    protected void throwForCommentExpressionEmptyException() {
        final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
        br.addNotice("The expression of FOR comment was empty!");
        br.addItem("Advice");
        br.addElement("Please confirm the FOR comment expression.");
        br.addElement("Your FOR comment might not have an expression.");
        br.addElement("For example:");
        br.addElement("  (x) - /*FOR */XXX_ID = /*#element*/3/*END*/");
        br.addElement("  (o) - /*FOR pmb.xxxList*/XXX_ID = /*#element*/3/*END*/");
        br.addItem("FOR Comment");
        br.addElement(_tokenizer.getToken());
        br.addItem("Specified SQL");
        br.addElement(_specifiedSql);
        final String msg = br.buildExceptionMessage();
        throw new ForCommentExpressionEmptyException(msg);
    }

    // ===================================================================================
    //                                                                         END Comment
    //                                                                         ===========
    protected boolean isEndComment(String content) {
        return content != null && "END".equals(content);
    }

    protected void parseEnd() {
        final int commentType = SqlTokenizer.COMMENT;
        while (SqlTokenizer.EOF != _tokenizer.next()) {
            if (_tokenizer.getTokenType() == commentType && isEndComment(_tokenizer.getToken())) {
                pop();
                return;
            }
            parseToken();
        }
        throwEndCommentNotFoundException();
    }

    protected void throwEndCommentNotFoundException() {
        final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
        br.addNotice("The end comment was not found!");
        br.addItem("Advice");
        br.addElement("Please confirm the parameter comment logic.");
        br.addElement("It may exist the parameter comment that DOESN'T have an end comment.");
        br.addElement("For example:");
        br.addElement("  (x): /*IF pmb.xxxId != null*/XXX_ID = /*pmb.xxxId*/3");
        br.addElement("  (o): /*IF pmb.xxxId != null*/XXX_ID = /*pmb.xxxId*/3/*END*/");
        br.addItem("Specified SQL");
        br.addElement(_specifiedSql);
        final String msg = br.buildExceptionMessage();
        throw new EndCommentNotFoundException(msg);
    }

    // ===================================================================================
    //                                                                    Bind or Embedded
    //                                                                    ================
    protected void parseBindVariable() { // for native binding, unused on DBFlute so checked later
        final String expr = _tokenizer.getToken();
        peek().addChild(createBindVariableNode(expr, null));
    }

    protected void parseCommentBindVariable() { // main binding on DBFlute
        final String expr = _tokenizer.getToken();
        final String testValue = _tokenizer.skipToken(true);
        if (expr.startsWith(EmbeddedVariableNode.PREFIX_NORMAL)) {
            if (expr.startsWith(EmbeddedVariableNode.PREFIX_REPLACE_ONLY)) { // replaceOnly
                peek().addChild(prepareReplaceOnlyEmbeddedVariableNode(expr, testValue, /*removePrefix*/true));
            } else if (expr.startsWith(EmbeddedVariableNode.PREFIX_TERMINAL_DOT)) { // terminalDot
                peek().addChild(prepareTerminalDotEmbeddedVariableNode(expr, testValue));
            } else { // normal
                peek().addChild(prepareNormalEmbeddedVariableNode(expr, testValue));
            }
        } else {
            final Node bindVariableNode;
            if (_switchBindingToReplaceOnlyEmbedded) { // false on DBFlute, for general purpose
                bindVariableNode = prepareReplaceOnlyEmbeddedVariableNode(expr, testValue, /*removePrefix*/false);
            } else { // always here on DBFlute
                bindVariableNode = createBindVariableNode(expr, testValue);
            }
            peek().addChild(bindVariableNode);
        }
    }

    // -----------------------------------------------------
    //                                     Embedded Variable
    //                                     -----------------
    protected EmbeddedVariableNode prepareReplaceOnlyEmbeddedVariableNode(String expr, String testValue, boolean removePrefix) {
        final String realExpr = removePrefix ? expr.substring(EmbeddedVariableNode.PREFIX_REPLACE_ONLY.length()) : expr;
        return createEmbeddedVariableNode(realExpr, testValue, /*replaceOnly*/true, false);
    }

    protected EmbeddedVariableNode prepareTerminalDotEmbeddedVariableNode(String expr, String testValue) {
        final String realExpr = expr.substring(EmbeddedVariableNode.PREFIX_TERMINAL_DOT.length());
        return createEmbeddedVariableNode(realExpr, testValue, false, /*terminalDot*/true);
    }

    protected EmbeddedVariableNode prepareNormalEmbeddedVariableNode(String expr, String testValue) {
        final String realExpr = expr.substring(EmbeddedVariableNode.PREFIX_NORMAL.length());
        return createEmbeddedVariableNode(realExpr, testValue, false, false);
    }

    protected EmbeddedVariableNode createEmbeddedVariableNode(String expr, String testValue, boolean replaceOnly, boolean terminalDot) {
        researchIfNeeds(_researchEmbeddedVariableCommentList, expr); // for research
        return newEmbeddedVariableNode(expr, testValue, _specifiedSql, _blockNullParameter, getNodeAdviceFactory(), replaceOnly,
                terminalDot, _overlookNativeBinding);
    }

    protected EmbeddedVariableNode newEmbeddedVariableNode(String expr, String testValue, String specifiedSql, boolean blockNullParameter,
            NodeAdviceFactory adviceFactory, boolean replaceOnly, boolean terminalDot, boolean overlookNativeBinding) {
        return new EmbeddedVariableNode(expr, testValue, specifiedSql, blockNullParameter, adviceFactory, replaceOnly, terminalDot,
                overlookNativeBinding);
    }

    // -----------------------------------------------------
    //                                         Bind Variable
    //                                         -------------
    protected BindVariableNode createBindVariableNode(String expr, String testValue) {
        researchIfNeeds(_researchBindVariableCommentList, expr); // for research
        return newBindVariableNode(expr, testValue, _specifiedSql, _blockNullParameter, getNodeAdviceFactory());
    }

    protected BindVariableNode newBindVariableNode(String expr, String testValue, String specifiedSql, boolean blockNullParameter,
            NodeAdviceFactory adviceFactory) {
        return new BindVariableNode(expr, testValue, specifiedSql, blockNullParameter, adviceFactory);
    }

    // ===================================================================================
    //                                                                        Various Node
    //                                                                        ============
    protected SqlConnectorNode createSqlConnectorNode(Node node, String connector, String sqlParts) {
        if (isNestedBegin(node)) { // basically nested if BEGIN node because checked before
            // connector adjustment of BEGIN is independent 
            return SqlConnectorNode.createSqlConnectorNodeAsIndependent(connector, sqlParts);
        } else {
            return SqlConnectorNode.createSqlConnectorNode(connector, sqlParts);
        }
    }

    protected SqlPartsNode createSqlPartsNodeOutOfConnector(Node node, String sqlParts) {
        if (isTopBegin(node)) { // top BEGIN only (nested goes 'else' statement)
            return SqlPartsNode.createSqlPartsNodeAsIndependent(sqlParts);
        } else {
            return createSqlPartsNode(sqlParts);
        }
    }

    protected SqlPartsNode createSqlPartsNodeThroughConnector(Node node, String sqlParts) {
        if (isNestedBegin(node)) { // basically nested if BEGIN node because checked before
            // connector adjustment of BEGIN is independent
            return SqlPartsNode.createSqlPartsNodeAsIndependent(sqlParts);
        } else {
            return createSqlPartsNode(sqlParts);
        }
    }

    protected SqlPartsNode createSqlPartsNode(String sqlParts) { // as plain
        return SqlPartsNode.createSqlPartsNode(sqlParts);
    }

    // ===================================================================================
    //                                                                          Node Stack
    //                                                                          ==========
    protected Node pop() {
        return (Node) _nodeStack.pop();
    }

    protected Node peek() {
        return (Node) _nodeStack.peek();
    }

    protected void push(Node node) {
        _nodeStack.push(node);
    }

    protected boolean isElseMode() {
        for (int i = 0; i < _nodeStack.size(); ++i) {
            if (_nodeStack.get(i) instanceof ElseNode) {
                return true;
            }
        }
        return false;
    }

    // ===================================================================================
    //                                                                   Bind Value Tracer
    //                                                                   =================
    protected NodeAdviceFactory getNodeAdviceFactory() {
        return _defaultNodeAdviceFactory; // you can switch it
    }

    // ===================================================================================
    //                                                                            Research
    //                                                                            ========
    /**
     * Research IF comments. (basically for research only, NOT for execution)
* This method should be called before calling analyze().
* The returned list is filled with IF comment after calling analyze(). * @return The list of IF comment. (NotNull) */ public List researchIfComment() { // should NOT be called with execution final List resultList = new ArrayList(); _researchIfCommentList = resultList; return resultList; } /** * Research bind variable comments. (basically for research only, NOT for execution)
* This method should be called before calling analyze().
* The returned list is filled with bind variable comment after calling analyze(). * @return The list of bind variable comment. (NotNull) */ public List researchBindVariableComment() { // should NOT be called with execution final List resultList = new ArrayList(); _researchBindVariableCommentList = resultList; return resultList; } /** * Research embedded variable comments. (basically for research only, NOT for execution)
* This method should be called before calling analyze().
* The returned list is filled with embedded variable comment after calling analyze(). * @return The list of embedded variable comment. (NotNull) */ public List researchEmbeddedVariableComment() { // should NOT be called with execution final List resultList = new ArrayList(); _researchEmbeddedVariableCommentList = resultList; return resultList; } protected void researchIfNeeds(List researchList, String expr) { if (researchList != null) { researchList.add(expr); } } // =================================================================================== // General Helper // ============== protected String replaceString(String text, String fromText, String toText) { return Srl.replace(text, fromText, toText); } // =================================================================================== // DisplaySql // ========== public static String convertTwoWaySql2DisplaySql(SqlAnalyzerFactory factory, String twoWaySql, Object arg, BoundDateDisplayStyle dateDisplayStyle) { final String[] argNames = new String[] { "pmb" }; final Class[] argTypes = new Class[] { arg.getClass() }; final Object[] args = new Object[] { arg }; return convertTwoWaySql2DisplaySql(factory, twoWaySql, argNames, argTypes, args, dateDisplayStyle); } public static String convertTwoWaySql2DisplaySql(SqlAnalyzerFactory factory, String twoWaySql, String[] argNames, Class[] argTypes, Object[] args, BoundDateDisplayStyle dateDisplayStyle) { final CommandContext context; { final SqlAnalyzer parser = createSqlAnalyzer4DisplaySql(factory, twoWaySql); final Node node = parser.analyze(); final CommandContextCreator creator = new CommandContextCreator(argNames, argTypes); context = creator.createCommandContext(args); node.accept(context); } final String preparedSql = context.getSql(); final DisplaySqlBuilder builder = new DisplaySqlBuilder(dateDisplayStyle); return builder.buildDisplaySql(preparedSql, context.getBindVariables()); } protected static SqlAnalyzer createSqlAnalyzer4DisplaySql(SqlAnalyzerFactory factory, String twoWaySql) { if (factory == null) { String msg = "The factory of SQL analyzer should exist."; throw new IllegalStateException(msg); } final boolean blockNullParameter = false; final SqlAnalyzer created = factory.create(twoWaySql, blockNullParameter); if (created != null) { return created; } String msg = "The factory should not return null:"; msg = msg + " sql=" + twoWaySql + " factory=" + factory; throw new IllegalStateException(msg); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy